Commit 0d73c81e authored by paul@ice.snake.net's avatar paul@ice.snake.net

Merge paul@bk-internal.mysql.com:/home/bk/mysql-4.1

into ice.snake.net:/Volumes/ice2/MySQL/bk/mysql-4.1
parents fe50dd18 56479967
......@@ -93,6 +93,7 @@ miguel@hegel.local
miguel@light.
miguel@light.local
miguel@sartre.local
mikron@mikael-ronstr-ms-dator.local
mmatthew@markslaptop.
monty@bitch.mysql.fi
monty@butch.
......
......@@ -1383,6 +1383,11 @@ AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [
--with-ndb-test Include the NDB Cluster ndbapi test programs],
[ndb_test="$withval"],
[ndb_test=no])
AC_ARG_WITH([ndb-docs],
[
--with-ndb-docs Include the NDB Cluster ndbapi and mgmapi documentation],
[ndb_docs="$withval"],
[ndb_docs=no])
AC_MSG_CHECKING([for NDB Cluster options])
AC_MSG_RESULT([])
......@@ -1422,6 +1427,17 @@ AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [
;;
esac
have_ndb_docs=no
case "$ndb_docs" in
yes )
AC_MSG_RESULT([-- including ndbapi and mgmapi documentation])
have_ndb_docs="yes"
;;
* )
AC_MSG_RESULT([-- not including ndbapi and mgmapi documentation])
;;
esac
AC_MSG_RESULT([done.])
])
......
......@@ -2919,16 +2919,23 @@ then
fi
AC_SUBST([ndb_transporter_opt_objs])
ndb_opt_subdirs=
ndb_bin_am_ldflags="-static"
if test X"$have_ndb_test" = Xyes
then
ndb_opt_test_subdirs="test"
ndb_opt_subdirs="test"
ndb_bin_am_ldflags=""
fi
if test X"$have_ndb_docs" = Xyes
then
ndb_opt_subdirs="$ndb_opt_subdirs docs"
ndb_bin_am_ldflags=""
fi
AC_SUBST([ndb_bin_am_ldflags])
AC_SUBST([ndb_opt_test_subdirs])
AC_SUBST([ndb_opt_subdirs])
AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl
ndb/src/Makefile ndb/src/common/Makefile dnl
ndb/docs/Makefile dnl
ndb/tools/Makefile dnl
ndb/src/common/debugger/Makefile ndb/src/common/debugger/signaldata/Makefile dnl
ndb/src/common/portlib/Makefile dnl
......
......@@ -1672,19 +1672,19 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
*/
/* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
static const unsigned MAX_DATE_REP_LENGTH= 5;
#define MAX_DATE_REP_LENGTH 5
/*
1 (length) + 1 (is negative) + 4 (day count) + 1 (hour)
+ 1 (minute) + 1 (seconds) + 4 (microseconds)
*/
static const unsigned MAX_TIME_REP_LENGTH= 13;
#define MAX_TIME_REP_LENGTH 13
/*
1 (length) + 2 (year) + 1 (month) + 1 (day) +
1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds)
*/
static const unsigned MAX_DATETIME_REP_LENGTH= 12;
#define MAX_DATETIME_REP_LENGTH 12
/**************** Misc utility functions ****************************/
......
......@@ -1439,7 +1439,7 @@ then
if [ -z "$USE_RUNNING_NDBCLUSTER" ]
then
echo "Starting ndbcluster"
./ndb/ndbcluster --initial --data-dir=$MYSQL_TEST_DIR/var || exit 1
./ndb/ndbcluster --small --discless --initial --data-dir=$MYSQL_TEST_DIR/var || exit 1
export NDB_CONNECTSTRING=`cat Ndb.cfg`
else
export NDB_CONNECTSTRING="$USE_RUNNING_NDBCLUSTER"
......
......@@ -4,9 +4,9 @@ testdir = $(benchdir_root)/mysql-test/ndb
test_SCRIPTS = ndbcluster
EXTRA_SCRIPTS = ndbcluster.sh
noinst_HEADERS = ndbcluster.sh
test_DATA = ndb_config_2_node.ini
dist_test_DATA = ndb_config_2_node.ini
SUFFIXES = .sh
......
[DB DEFAULT]
#NoOfFragmentLogfiles: 1
#TimeBetweenLocalCheckpoints: 31
NoOfReplicas: 2
MaxNoOfConcurrentOperations: 100000
MaxNoOfConcurrentOperations: CHOOSE_MaxNoOfConcurrentOperations
DataMemory: CHOOSE_DataMemory
IndexMemory: CHOOSE_IndexMemory
Discless: CHOOSE_Discless
[COMPUTER]
Id: 1
......
......@@ -41,6 +41,12 @@ pidfile=ndbcluster.pid
cfgfile=Ndb.cfg
stop_ndb=
initial_ndb=
status_ndb=
ndb_discless=0
ndb_con_op=100000
ndb_dmem=80M
ndb_imem=24M
while test $# -gt 0; do
case "$1" in
......@@ -51,6 +57,17 @@ while test $# -gt 0; do
flags_ndb=$flags_ndb" -i"
initial_ndb=1
;;
--status)
status_ndb=1
;;
--small)
ndb_con_op=10000
ndb_dmem=40M
ndb_imem=12M
;;
--discless)
ndb_discless=1
;;
--data-dir=*)
fsdir=`echo "$1" | sed -e "s;--data-dir=;;"`
;;
......@@ -121,6 +138,10 @@ NDB_CONNECTSTRING=$NDB_CONNECTSTRING_BASE$NDB_ID
if [ $initial_ndb ] ; then
sed \
-e s,"CHOOSE_MaxNoOfConcurrentOperations",$ndb_con_op,g \
-e s,"CHOOSE_DataMemory",$ndb_dmem,g \
-e s,"CHOOSE_IndexMemory",$ndb_imem,g \
-e s,"CHOOSE_Discless",$ndb_discless,g \
-e s,"CHOOSE_HOSTNAME_".*,"$ndb_host",g \
-e s,"CHOOSE_FILESYSTEM_NODE_2","$fs_name_2",g \
-e s,"CHOOSE_FILESYSTEM_NODE_3","$fs_name_3",g \
......@@ -140,6 +161,7 @@ cat `find $fs_ndb -name 'node*.pid'` > $pidfile
NDB_ID="2"
NDB_CONNECTSTRING=$NDB_CONNECTSTRING_BASE$NDB_ID
echo "Starting ndbd connectstring=\""$NDB_CONNECTSTRING\"
( cd $fs_ndb_2 ; echo $NDB_CONNECTSTRING > $cfgfile ; $exec_ndb -d $flags_ndb & )
cat `find $fs_ndb -name 'node*.pid'` > $pidfile
......@@ -148,17 +170,14 @@ cat `find $fs_ndb -name 'node*.pid'` > $pidfile
NDB_ID="3"
NDB_CONNECTSTRING=$NDB_CONNECTSTRING_BASE$NDB_ID
echo "Starting ndbd connectstring=\""$NDB_CONNECTSTRING\"
( cd $fs_ndb_3 ; echo $NDB_CONNECTSTRING > $cfgfile ; $exec_ndb -d $flags_ndb & )
cat `find $fs_ndb -name 'node*.pid'` > $pidfile
# Start management client
sleep 10
echo "show" | $exec_mgmtclient $ndb_host $ndb_port
# test if Ndb Cluster starts properly
echo "Waiting for started..."
NDB_ID="11"
NDB_CONNECTSTRING=$NDB_CONNECTSTRING_BASE$NDB_ID
if ( $exec_waiter ) | grep "NDBT_ProgramExit: 0 - OK"; then :; else
......@@ -169,6 +188,14 @@ fi
echo $NDB_CONNECTSTRING > $cfgfile
cat `find $fs_ndb -name 'node*.pid'` > $pidfile
status_ndbcluster
}
status_ndbcluster() {
# Start management client
echo "show" | $exec_mgmtclient $ndb_host $ndb_port
}
stop_default_ndbcluster() {
......@@ -195,12 +222,17 @@ echo "all stop" | $exec_mgmtclient
sleep 5
if [ -f $pidfile ] ; then
kill `cat $pidfile`
kill `cat $pidfile` 2> /dev/null
rm $pidfile
fi
}
if [ $status_ndb ] ; then
status_ndbcluster
exit 0
fi
if [ $stop_ndb ] ; then
stop_default_ndbcluster
else
......
......@@ -157,11 +157,8 @@ grp group_concat(c)
3 D,D,E
4
5 NULL
Warnings:
Warning 1260 1 line(s) was(were) cut by group_concat()
show warnings;
Level Code Message
Warning 1260 1 line(s) was(were) cut by group_concat()
set group_concat_max_len = 1024;
select group_concat(sum(a)) from t1 group by grp;
ERROR HY000: Invalid use of group function
......@@ -310,3 +307,14 @@ GROUP_CONCAT(t1.a*t2.a ORDER BY t2.a)
1,2
2,4
DROP TABLE t1, t2;
CREATE TABLE t1 (a char(4));
INSERT INTO t1 VALUES ('John'), ('Anna'), ('Bill');
SELECT GROUP_CONCAT(a SEPARATOR '||') AS names FROM t1
HAVING names LIKE '%An%';
names
John||Anna||Bill
SELECT GROUP_CONCAT(a SEPARATOR '###') AS names FROM t1
HAVING LEFT(names, 1) ='J';
names
John###Anna###Bill
DROP TABLE t1;
......@@ -189,3 +189,15 @@ INSERT INTO t1 VALUES (1), (2);
INSERT INTO t2 VALUES (1), (2);
SELECT GROUP_CONCAT(t1.a*t2.a ORDER BY t2.a) FROM t1, t2 GROUP BY t1.a;
DROP TABLE t1, t2;
#
# Bug #4035: group_concat() and HAVING
#
CREATE TABLE t1 (a char(4));
INSERT INTO t1 VALUES ('John'), ('Anna'), ('Bill');
SELECT GROUP_CONCAT(a SEPARATOR '||') AS names FROM t1
HAVING names LIKE '%An%';
SELECT GROUP_CONCAT(a SEPARATOR '###') AS names FROM t1
HAVING LEFT(names, 1) ='J';
DROP TABLE t1;
SUBDIRS = src tools . include $(ndb_opt_test_subdirs)
SUBDIRS = src tools . include @ndb_opt_subdirs@
DIST_SUBDIRS = src tools include test docs
EXTRA_DIST = config
include $(top_srcdir)/ndb/config/common.mk.am
......
DOXYDIR = doxygen
noinst_HEADERS = $(DOXYDIR)/predoxy.pl $(DOXYDIR)/postdoxy.pl $(DOXYDIR)/Doxyfile.ndbapi $(DOXYDIR)/Doxyfile.mgmapi $(DOXYDIR)/header.ndbapi.tex $(DOXYDIR)/header.mgmapi.tex
all: do-check ndbapidoc mgmapidoc
DOXYDIR = doxygen
DOXYTMP = .doxytmp
DOXYOUT = .doxyout
......@@ -35,7 +36,7 @@ do-check:
#
ndbapidoc: ndbapi.pdf
ndbapi.pdf: $(top_srcdir)/ndb/include/ndb_version.h
ndbapi.pdf: $(noinst_HEADERS)
@set -x; \
export NDB_RELEASE=$(NDB_RELEASE) \
@RM@ -f ndbapi.pdf ndbapi.html; \
......@@ -59,7 +60,7 @@ ndbapi.pdf: $(top_srcdir)/ndb/include/ndb_version.h
#
mgmapidoc: mgmapi.pdf
mgmapi.pdf: $(top_srcdir)/ndb/include/ndb_version.h
mgmapi.pdf: $(noinst_HEADERS)
@set -x; \
export NDB_RELEASE=$(NDB_RELEASE) \
@RM@ -f mgmapi.pdf mgmapi.html; \
......
......@@ -91,4 +91,9 @@
#define MAX_TTREE_PREF_SIZE 4 // words in min/max prefix each
#define MAX_TTREE_NODE_SLACK 3 // diff between max and min occupancy
/*
* Blobs.
*/
#define NDB_BLOB_HEAD_SIZE 2 // sizeof(NdbBlob::Head) >> 2
#endif
......@@ -307,7 +307,9 @@ public:
ExtBinary = NdbSqlUtil::Type::Binary,
ExtVarbinary = NdbSqlUtil::Type::Varbinary,
ExtDatetime = NdbSqlUtil::Type::Datetime,
ExtTimespec = NdbSqlUtil::Type::Timespec
ExtTimespec = NdbSqlUtil::Type::Timespec,
ExtBlob = NdbSqlUtil::Type::Blob,
ExtClob = NdbSqlUtil::Type::Clob
};
// Attribute data interpretation
......@@ -430,6 +432,13 @@ public:
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 12 * AttributeExtLength;
return true;
case DictTabInfo::ExtBlob:
case DictTabInfo::ExtClob:
AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
// head + inline part [ attr precision ]
AttributeArraySize = (NDB_BLOB_HEAD_SIZE << 2) + AttributeExtPrecision;
return true;
};
return false;
}
......
......@@ -74,6 +74,8 @@
#define CFG_LOGLEVEL_GREP 146
#define CFG_LOG_DESTINATION 147
#define CFG_DB_DISCLESS 148
#define CFG_NODE_ARBIT_RANK 200
#define CFG_NODE_ARBIT_DELAY 201
......
......@@ -879,6 +879,7 @@ class NdbScanReceiver;
class Table;
class BaseString;
class NdbEventOperation;
class NdbBlob;
typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
......@@ -964,6 +965,7 @@ class Ndb
friend class NdbIndexOperation;
friend class NdbDictionaryImpl;
friend class NdbDictInterface;
friend class NdbBlob;
public:
/**
......@@ -1452,6 +1454,7 @@ private:
NdbIndexOperation* getIndexOperation();// Get an index operation from idle
class NdbGlobalEventBufferHandle* getGlobalEventBufferHandle();
NdbBlob* getNdbBlob();// Get a blob handle etc
void releaseSignal(NdbApiSignal* anApiSignal);
void releaseSignalsInList(NdbApiSignal** pList);
......@@ -1463,6 +1466,7 @@ private:
void releaseRecAttr (NdbRecAttr* aRecAttr);
void releaseOperation(NdbOperation* anOperation);
void releaseScanOperation(NdbScanOperation* aScanOperation);
void releaseNdbBlob(NdbBlob* aBlob);
void check_send_timeout();
void remove_sent_list(Uint32);
......@@ -1505,6 +1509,7 @@ private:
void freeNdbSubroutine();// Free the first idle NdbSubroutine obj
void freeNdbCall(); // Free the first idle NdbCall obj
void freeNdbScanRec(); // Free the first idle NdbScanRec obj
void freeNdbBlob(); // Free the first etc
NdbConnection* getNdbCon(); // Get a connection from idle list
......@@ -1613,6 +1618,7 @@ private:
NdbSubroutine* theSubroutineList; // First subroutine descriptor in
NdbCall* theCallList; // First call descriptor in list
NdbScanReceiver* theScanList;
NdbBlob* theNdbBlobIdleList;
Uint32 theMyRef; // My block reference
Uint32 theNode; // The node number of our node
......
......@@ -28,4 +28,5 @@
#include "NdbDictionary.hpp"
#include "NdbEventOperation.hpp"
#include "NdbPool.hpp"
#include "NdbBlob.hpp"
#endif
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef NdbBlob_H
#define NdbBlob_H
#include <ndb_types.h>
#include <NdbDictionary.hpp>
#include <NdbConnection.hpp>
#include <NdbError.hpp>
class Ndb;
class NdbConnection;
class NdbOperation;
class NdbRecAttr;
class NdbTableImpl;
class NdbColumnImpl;
/**
* @class NdbBlob
* @brief Blob handle
*
* Blob data is stored in 2 places:
*
* - "header" and "inline bytes" stored in the blob attribute
* - "blob parts" stored in a separate table NDB$BLOB_<t>_<v>_<c>
*
* Inline and part sizes can be set via NdbDictionary::Column methods
* when the table is created.
*
* NdbBlob is a blob handle. To access blob data, the handle must be
* created using NdbOperation::getBlobHandle in operation prepare phase.
* The handle has following states:
*
* - prepared: before the operation is executed
* - active: after execute or next result but before transaction commit
* - closed: after transaction commit
* - invalid: after rollback or transaction close
*
* NdbBlob supports 2 styles of data access:
*
* - in prepare phase, NdbBlob methods getValue and setValue are used to
* prepare a read or write of a single blob value of known size
*
* - in active phase, NdbBlob methods readData and writeData are used to
* read or write blob data of undetermined size
*
* NdbBlob methods return -1 on error and 0 on success, and use output
* parameters when necessary.
*
* Notes:
* - table and its blob part tables are not created atomically
* - blob data operations take effect at next transaction execute
* - NdbBlob may need to do implicit executes on the transaction
* - read and write of complete parts is much more efficient
* - scan must use the "new" interface NdbScanOperation
* - scan with blobs applies hold-read-lock (at minimum)
* - to update a blob in a read op requires exclusive tuple lock
* - update op in scan must do its own getBlobHandle
* - delete creates implicit, not-accessible blob handles
* - NdbOperation::writeTuple does not support blobs
* - there is no support for an asynchronous interface
*
* Bugs / limitations:
* - scan must use exclusive locking for now
*
* Todo:
* - add scan method hold-read-lock-until-next + return-keyinfo
* - better check of keyinfo length when setting keys
* - better check of allowed blob op vs locking mode
*/
class NdbBlob {
public:
enum State {
Idle = 0,
Prepared = 1,
Active = 2,
Closed = 3,
Invalid = 9
};
State getState();
/**
* Prepare to read blob value. The value is available after execute.
* Use isNull to check for NULL and getLength to get the real length
* and to check for truncation. Sets current read/write position to
* after the data read.
*/
int getValue(void* data, Uint32 bytes);
/**
* Prepare to insert or update blob value. An existing longer blob
* value will be truncated. The data buffer must remain valid until
* execute. Sets current read/write position to after the data. Set
* data to null pointer (0) to create a NULL value.
*/
int setValue(const void* data, Uint32 bytes);
/**
* Check if blob is null.
*/
int getNull(bool& isNull);
/**
* Set blob to NULL.
*/
int setNull();
/**
* Get current length in bytes. Use isNull to distinguish between
* length 0 blob and NULL blob.
*/
int getLength(Uint64& length);
/**
* Truncate blob to given length. Has no effect if the length is
* larger than current length.
*/
int truncate(Uint64 length = 0);
/**
* Get current read/write position.
*/
int getPos(Uint64& pos);
/**
* Set read/write position. Must be between 0 and current length.
* "Sparse blobs" are not supported.
*/
int setPos(Uint64 pos);
/**
* Read at current position and set new position to first byte after
* the data read. A read past blob end returns actual number of bytes
* read in the in/out bytes parameter.
*/
int readData(void* data, Uint32& bytes);
/**
* Read at given position. Does not use or update current position.
*/
int readData(Uint64 pos, void* data, Uint32& bytes);
/**
* Write at current position and set new position to first byte after
* the data written. A write past blob end extends the blob value.
*/
int writeData(const void* data, Uint32 bytes);
/**
* Write at given position. Does not use or update current position.
*/
int writeData(Uint64 pos, const void* data, Uint32 bytes);
/**
* Return the blob column.
*/
const NdbDictionary::Column* getColumn();
/**
* Get blob parts table name. Useful only to test programs.
*/
static const unsigned BlobTableNameSize = 40;
static int getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName);
/**
* Return error object. The error may be blob specific (below) or may
* be copied from a failed implicit operation.
*/
const NdbError& getNdbError() const;
// "Invalid blob attributes or invalid blob parts table"
static const int ErrTable = 4263;
// "Invalid usage of blob attribute"
static const int ErrUsage = 4264;
// "Method is not valid in current blob state"
static const int ErrState = 4265;
// "Invalid blob seek position"
static const int ErrSeek = 4266;
// "Corrupted blob value"
static const int ErrCorrupt = 4267;
// "Error in blob head update forced rollback of transaction"
static const int ErrAbort = 4268;
// "Unknown blob error"
static const int ErrUnknown = 4269;
private:
friend class Ndb;
friend class NdbConnection;
friend class NdbOperation;
friend class NdbScanOperation;
friend class NdbDictionaryImpl;
// state
State theState;
void setState(State newState);
// define blob table
static void getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c);
static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c);
// table name
char theBlobTableName[BlobTableNameSize];
// ndb api stuff
Ndb* theNdb;
NdbConnection* theNdbCon;
NdbOperation* theNdbOp;
NdbTableImpl* theTable;
NdbTableImpl* theAccessTable;
const NdbColumnImpl* theColumn;
char theFillChar;
// sizes
Uint32 theInlineSize;
Uint32 thePartSize;
Uint32 theStripeSize;
// getValue/setValue
bool theGetFlag;
char* theGetBuf;
bool theSetFlag;
const char* theSetBuf;
Uint32 theGetSetBytes;
// head
struct Head {
Uint64 length;
};
// buffers
struct Buf {
char* data;
unsigned size;
unsigned maxsize;
Buf();
~Buf();
void alloc(unsigned n);
};
Buf theKeyBuf;
Buf theAccessKeyBuf;
Buf theHeadInlineBuf;
Buf thePartBuf;
Head* theHead;
char* theInlineData;
NdbRecAttr* theHeadInlineRecAttr;
bool theHeadInlineUpdateFlag;
bool theNewPartFlag;
// length and read/write position
int theNullFlag;
Uint64 theLength;
Uint64 thePos;
// errors
NdbError theError;
// for keeping in lists
NdbBlob* theNext;
// initialization
NdbBlob();
void init();
void release();
// classify operations
bool isTableOp();
bool isIndexOp();
bool isKeyOp();
bool isReadOp();
bool isInsertOp();
bool isUpdateOp();
bool isDeleteOp();
bool isScanOp();
// computations
Uint32 getPartNumber(Uint64 pos);
Uint32 getPartCount();
Uint32 getDistKey(Uint32 part);
// getters and setters
int getTableKeyValue(NdbOperation* anOp);
int setTableKeyValue(NdbOperation* anOp);
int setAccessKeyValue(NdbOperation* anOp);
int setPartKeyValue(NdbOperation* anOp, Uint32 part);
int getHeadInlineValue(NdbOperation* anOp);
void getHeadFromRecAttr();
int setHeadInlineValue(NdbOperation* anOp);
// data operations
int readDataPrivate(Uint64 pos, char* buf, Uint32& bytes);
int writeDataPrivate(Uint64 pos, const char* buf, Uint32 bytes);
int readParts(char* buf, Uint32 part, Uint32 count);
int insertParts(const char* buf, Uint32 part, Uint32 count);
int updateParts(const char* buf, Uint32 part, Uint32 count);
int deleteParts(Uint32 part, Uint32 count);
// blob handle maintenance
int atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn);
int preExecute(ExecType anExecType, bool& batch);
int postExecute(ExecType anExecType);
int preCommit();
int atNextResult();
// errors
void setErrorCode(int anErrorCode, bool invalidFlag = true);
void setErrorCode(NdbOperation* anOp, bool invalidFlag = true);
void setErrorCode(NdbConnection* aCon, bool invalidFlag = true);
#ifdef VM_TRACE
friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
#endif
};
#endif
......@@ -28,6 +28,7 @@ class NdbIndexOperation;
class NdbApiSignal;
class Ndb;
class NdbScanReceiver;
class NdbBlob;
/**
......@@ -160,6 +161,7 @@ class NdbConnection
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbScanReceiver;
friend class NdbBlob;
public:
......@@ -536,6 +538,10 @@ private:
~NdbConnection();
void init(); // Initialize connection object for new transaction
int executeNoBlobs(ExecType execType,
AbortOption abortOption = AbortOnError,
int force = 0 );
/**
* Set Connected node id
......@@ -625,10 +631,12 @@ private:
void setOperationErrorCodeAbort(int anErrorCode);
int checkMagicNumber(); // Verify correct object
NdbOperation* getNdbOperation(class NdbTableImpl* aTable);
NdbOperation* getNdbOperation(class NdbTableImpl* aTable,
NdbOperation* aNextOp = 0);
NdbScanOperation* getNdbScanOperation(class NdbTableImpl* aTable);
NdbIndexOperation* getNdbIndexOperation(class NdbIndexImpl* anIndex,
class NdbTableImpl* aTable);
class NdbTableImpl* aTable,
NdbOperation* aNextOp = 0);
void handleExecuteCompletion();
......@@ -730,6 +738,8 @@ private:
// nextScanResult.
NdbOperation* theScanningOp; // The operation actually performing the scan
Uint32 theBuddyConPtr;
// optim: any blobs
bool theBlobFlag;
static void sendTC_COMMIT_ACK(NdbApiSignal *,
Uint32 transId1, Uint32 transId2,
......
......@@ -182,7 +182,8 @@ public:
Varbinary, ///< Max len
Datetime, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes )
Timespec, ///< Precision down to 1 nsec(sizeof(Datetime) == 12 bytes )
Blob ///< Binary large object (see NdbBlob)
Blob, ///< Binary large object (see NdbBlob)
Clob ///< Text blob
};
/**
......@@ -297,7 +298,29 @@ public:
* Array length for column or max length for variable length arrays.
*/
int getLength() const;
/**
* For blob, set or get "inline size" i.e. number of initial bytes
* to store in table's blob attribute. This part is normally in
* main memory and can be indexed and interpreted.
*/
void setInlineSize(int size) { setPrecision(size); }
int getInlineSize() const { return getPrecision(); }
/**
* For blob, set or get "part size" i.e. number of bytes to store in
* each tuple of the "blob table". Must be less than 64k.
*/
void setPartSize(int size) { setScale(size); }
int getPartSize() const { return getScale(); }
/**
* For blob, set or get "stripe size" i.e. number of consecutive
* <em>parts</em> to store in each node group.
*/
void setStripeSize(int size) { setLength(size); }
int getStripeSize() const { return getLength(); }
/**
* Get size of element
*/
......@@ -1029,6 +1052,7 @@ public:
private:
friend class NdbDictionaryImpl;
friend class UtilTransactions;
friend class NdbBlob;
class NdbDictionaryImpl & m_impl;
Dictionary(NdbDictionaryImpl&);
const Table * getIndexTable(const char * indexName,
......
......@@ -28,6 +28,7 @@ class NdbRecAttr;
class NdbOperation;
class NdbConnection;
class NdbColumnImpl;
class NdbBlob;
/**
* @class NdbOperation
......@@ -41,7 +42,8 @@ class NdbOperation
friend class NdbScanReceiver;
friend class NdbScanFilter;
friend class NdbScanFilterImpl;
friend class NdbBlob;
public:
/**
* @name Define Standard Operation Type
......@@ -525,6 +527,17 @@ public:
virtual int setValue(Uint32 anAttrId, Int64 aValue);
virtual int setValue(Uint32 anAttrId, float aValue);
virtual int setValue(Uint32 anAttrId, double aValue);
/**
* This method replaces getValue/setValue for blobs. It creates
* a blob handle NdbBlob. A second call with same argument returns
* the previously created handle. The handle is linked to the
* operation and is maintained automatically.
*
* See NdbBlob for details.
*/
virtual NdbBlob* getBlobHandle(const char* anAttrName);
virtual NdbBlob* getBlobHandle(Uint32 anAttrId);
/** @} *********************************************************************/
/**
......@@ -832,6 +845,11 @@ public:
*/
int getNdbErrorLine();
/**
* Get table name of this operation.
*/
const char* getTableName() const;
/** @} *********************************************************************/
/**
......@@ -953,6 +971,7 @@ protected:
Uint32 len);
NdbRecAttr* getValue(const NdbColumnImpl* anAttrObject, char* aValue = 0);
int setValue(const NdbColumnImpl* anAttrObject, const char* aValue, Uint32 len);
NdbBlob* getBlobHandle(NdbConnection* aCon, const NdbColumnImpl* anAttrObject);
int incValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
int incValue(const NdbColumnImpl* anAttrObject, Uint64 aValue);
int subValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
......@@ -997,6 +1016,10 @@ protected:
NdbOperation*
takeOverScanOp(OperationType opType, NdbConnection* updateTrans);
// get table or index key from prepared signals
int getKeyFromTCREQ(Uint32* data, unsigned size);
int getKeyFromKEYINFO20(Uint32* data, unsigned size);
/******************************************************************************
* These are the private variables that are defined in the operation objects.
*****************************************************************************/
......@@ -1095,6 +1118,8 @@ protected:
// saveBoundATTRINFO() moves ATTRINFO here when setBound() is ready
NdbApiSignal* theBoundATTRINFO;
Uint32 theTotalBoundAI_Len;
// Blobs in this operation
NdbBlob* theBlobList;
};
......
......@@ -33,6 +33,8 @@
#include <NdbOperation.hpp>
#include <NdbCursorOperation.hpp>
class NdbBlob;
/**
* @class NdbScanOperation
* @brief Class of scan operations for use in transactions.
......@@ -82,6 +84,10 @@ public:
int setValue(Uint32 anAttrId, float aValue);
int setValue(Uint32 anAttrId, double aValue);
#endif
NdbBlob* getBlobHandle(const char* anAttrName);
NdbBlob* getBlobHandle(Uint32 anAttrId);
private:
NdbScanOperation(Ndb* aNdb);
......
......@@ -19,6 +19,7 @@
#include <string.h>
#include <ndb_types.h>
#include <kernel/ndb_limits.h>
class NdbSqlUtil {
public:
......@@ -77,7 +78,9 @@ public:
Binary, // Len
Varbinary, // Max len
Datetime, // Precision down to 1 sec (size 8 bytes)
Timespec // Precision down to 1 nsec (size 12 bytes)
Timespec, // Precision down to 1 nsec (size 12 bytes)
Blob, // Blob
Clob // Text blob
};
Enum m_typeId;
Cmp* m_cmp; // set to NULL if cmp not implemented
......@@ -121,6 +124,8 @@ private:
static Cmp cmpVarbinary;
static Cmp cmpDatetime;
static Cmp cmpTimespec;
static Cmp cmpBlob;
static Cmp cmpClob;
};
inline int
......@@ -350,6 +355,23 @@ NdbSqlUtil::cmp(Uint32 typeId, const Uint32* p1, const Uint32* p2, Uint32 full,
break;
case Type::Timespec: // XXX fix this
break;
case Type::Blob: // XXX fix
break;
case Type::Clob:
{
// skip blob head, the rest is varchar
const unsigned skip = NDB_BLOB_HEAD_SIZE;
if (size >= skip + 1) {
union { const Uint32* p; const char* v; } u1, u2;
u1.p = p1 + skip;
u2.p = p2 + skip;
// length in first 2 bytes
int k = strncmp(u1.v + 2, u2.v + 2, ((size - skip) << 2) - 2);
return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
}
return CmpUnknown;
}
break;
}
return CmpError;
}
......
......@@ -888,6 +888,19 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
1,
0x7FFFFFFF },
{
CFG_DB_DISCLESS,
"Discless",
"DB",
"Run wo/ disk",
ConfigInfo::USED,
true,
ConfigInfo::BOOL,
0,
0,
1},
{
CFG_DB_ARBIT_TIMEOUT,
"ArbitrationTimeout",
......
......@@ -155,6 +155,14 @@ NdbSqlUtil::m_typeList[] = {
{
Type::Timespec,
NULL // cmpTimespec
},
{
Type::Blob,
NULL // cmpDatetime
},
{
Type::Clob,
cmpClob
}
};
......@@ -284,6 +292,18 @@ NdbSqlUtil::cmpTimespec(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32
return cmp(Type::Timespec, p1, p2, full, size);
}
int
NdbSqlUtil::cmpBlob(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
{
return cmp(Type::Blob, p1, p2, full, size);
}
int
NdbSqlUtil::cmpClob(const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
{
return cmp(Type::Clob, p1, p2, full, size);
}
#ifdef NDB_SQL_UTIL_TEST
#include <NdbTick.h>
......
......@@ -72,14 +72,15 @@ SimBlockList::load(const Configuration & conf){
SimulatedBlock * fs = 0;
{
char buf[100];
if(NdbEnv_GetEnv("NDB_NOFS", buf, 100) == 0){
fs = new (A_VALUE) Ndbfs(conf);
} else {
Uint32 dl;
const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator();
if(p && !ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &dl) && dl){
fs = new (A_VALUE) VoidFs(conf);
} else {
fs = new (A_VALUE) Ndbfs(conf);
}
}
theList[0] = new (A_VALUE) Dbacc(conf);
theList[1] = new (A_VALUE) Cmvmi(conf);
theList[2] = fs;
......
......@@ -2736,8 +2736,8 @@ void Dbtc::execTCKEYREQ(Signal* signal)
case ZUPDATE:
jam();
if (Tattrlength == 0) {
TCKEY_abort(signal, 5);
return;
//TCKEY_abort(signal, 5);
//return;
}//if
/*---------------------------------------------------------------------*/
// The missing break is intentional since we also want to set the opLock
......@@ -5950,62 +5950,70 @@ void Dbtc::checkStartFragTimeout(Signal* signal)
/* BEEN DELAYED FOR SO LONG THAT WE ARE FORCED TO PERFORM */
/* SOME ACTION, EITHER ABORT OR RESEND OR REMOVE A NODE FROM */
/* THE WAITING PART OF A PROTOCOL. */
/*
The algorithm used here is to check 1024 transactions at a time before
doing a real-time break.
To avoid aborting both transactions in a deadlock detected by time-out
we insert a random extra time-out of upto 630 ms by using the lowest
six bits of the api connect reference.
We spread it out from 0 to 630 ms if base time-out is larger than 3 sec,
we spread it out from 0 to 70 ms if base time-out is smaller than 300 msec,
and otherwise we spread it out 310 ms.
*/
/*------------------------------------------------------------------*/
void Dbtc::timeOutLoopStartLab(Signal* signal, Uint32 TapiConPtr)
void Dbtc::timeOutLoopStartLab(Signal* signal, Uint32 api_con_ptr)
{
UintR texpiredTime[8];
UintR TloopCount = 0;
Uint32 end_ptr, time_passed, time_out_value, mask_value;
const Uint32 api_con_sz= capiConnectFilesize;
const Uint32 tc_timer= ctcTimer;
const Uint32 time_out_param= ctimeOutValue;
ctimeOutCheckHeartbeat = ctcTimer;
ctimeOutCheckHeartbeat = tc_timer;
const Uint32 TapiConSz = capiConnectFilesize;
const Uint32 TtcTimer = ctcTimer;
const Uint32 TtimeOutValue = ctimeOutValue;
while ((TapiConPtr + 8) < TapiConSz) {
jam();
texpiredTime[0] = TtcTimer - getApiConTimer(TapiConPtr + 0);
texpiredTime[1] = TtcTimer - getApiConTimer(TapiConPtr + 1);
texpiredTime[2] = TtcTimer - getApiConTimer(TapiConPtr + 2);
texpiredTime[3] = TtcTimer - getApiConTimer(TapiConPtr + 3);
texpiredTime[4] = TtcTimer - getApiConTimer(TapiConPtr + 4);
texpiredTime[5] = TtcTimer - getApiConTimer(TapiConPtr + 5);
texpiredTime[6] = TtcTimer - getApiConTimer(TapiConPtr + 6);
texpiredTime[7] = TtcTimer - getApiConTimer(TapiConPtr + 7);
for (Uint32 Ti = 0; Ti < 8; Ti++) {
if (getApiConTimer(TapiConPtr + Ti) != 0) {
if (texpiredTime[Ti] > TtimeOutValue) {
jam();
timeOutFoundLab(signal, TapiConPtr + Ti);
return;
}//if
}//if
}//for
TapiConPtr += 8;
if (TloopCount++ > 128) {
jam();
sendContinueTimeOutControl(signal, TapiConPtr);
return;
}//if
}//while
for ( ; TapiConPtr < TapiConSz; TapiConPtr++) {
if (api_con_ptr + 1024 < api_con_sz) {
jam();
if (getApiConTimer(TapiConPtr) != 0) {
texpiredTime[0] = TtcTimer - getApiConTimer(TapiConPtr);
if (texpiredTime[0] > TtimeOutValue) {
end_ptr= api_con_ptr + 1024;
} else {
jam();
end_ptr= api_con_sz;
}
if (time_out_param > 300) {
jam();
mask_value= 63;
} else if (time_out_param < 30) {
jam();
mask_value= 7;
} else {
jam();
mask_value= 31;
}
for ( ; api_con_ptr < end_ptr; api_con_ptr++) {
Uint32 api_timer= getApiConTimer(api_con_ptr);
jam();
if (api_timer != 0) {
time_out_value= time_out_param + (api_con_ptr & mask_value);
time_passed= tc_timer - api_timer;
if (time_passed > time_out_value) {
jam();
timeOutFoundLab(signal, TapiConPtr);
timeOutFoundLab(signal, api_con_ptr);
return;
}//if
}//if
}//for
/*------------------------------------------------------------------*/
/* */
/* WE HAVE NOW CHECKED ALL TRANSACTIONS FOR TIME-OUT AND ALSO */
/* STARTED TIME-OUT HANDLING OF THOSE WE FOUND. WE ARE NOW */
/* READY AND CAN WAIT FOR THE NEXT TIME-OUT CHECK. */
/*------------------------------------------------------------------*/
ctimeOutCheckActive = TOCS_FALSE;
}
}
}
if (api_con_ptr == api_con_sz) {
jam();
/*------------------------------------------------------------------*/
/* */
/* WE HAVE NOW CHECKED ALL TRANSACTIONS FOR TIME-OUT AND ALSO */
/* STARTED TIME-OUT HANDLING OF THOSE WE FOUND. WE ARE NOW */
/* READY AND CAN WAIT FOR THE NEXT TIME-OUT CHECK. */
/*------------------------------------------------------------------*/
ctimeOutCheckActive = TOCS_FALSE;
} else {
jam();
sendContinueTimeOutControl(signal, api_con_ptr);
}
return;
}//Dbtc::timeOutLoopStartLab()
void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr)
......
......@@ -35,7 +35,8 @@ libndbapi_la_SOURCES = \
NdbReceiver.cpp \
NdbDictionary.cpp \
NdbDictionaryImpl.cpp \
DictCache.cpp
DictCache.cpp \
NdbBlob.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi
......
......@@ -58,7 +58,8 @@ SOURCES = \
NdbSchemaOp.cpp \
NdbUtil.cpp \
NdbReceiver.cpp \
NdbDictionary.cpp NdbDictionaryImpl.cpp DictCache.cpp
NdbDictionary.cpp NdbDictionaryImpl.cpp DictCache.cpp \
NdbBlob.cpp
include $(NDB_TOP)/Epilogue.mk
......
This diff is collapsed.
......@@ -35,6 +35,7 @@ Adjust: 971022 UABMNST First version.
#include "NdbApiSignal.hpp"
#include "TransporterFacade.hpp"
#include "API.hpp"
#include "NdbBlob.hpp"
#include <ndb_limits.h>
#include <signaldata/TcKeyConf.hpp>
......@@ -89,7 +90,8 @@ NdbConnection::NdbConnection( Ndb* aNdb ) :
theCurrentScanRec(NULL),
thePreviousScanRec(NULL),
theScanningOp(NULL),
theBuddyConPtr(0xFFFFFFFF)
theBuddyConPtr(0xFFFFFFFF),
theBlobFlag(false)
{
theListState = NotInList;
theError.code = 0;
......@@ -152,6 +154,8 @@ NdbConnection::init()
m_theLastCursorOperation = NULL;
m_firstExecutedCursorOp = 0;
theBuddyConPtr = 0xFFFFFFFF;
//
theBlobFlag = false;
}//NdbConnection::init()
/*****************************************************************************
......@@ -250,6 +254,86 @@ int
NdbConnection::execute(ExecType aTypeOfExec,
AbortOption abortOption,
int forceSend)
{
if (! theBlobFlag)
return executeNoBlobs(aTypeOfExec, abortOption, forceSend);
// execute prepared ops in batches, as requested by blobs
ExecType tExecType;
NdbOperation* tPrepOp;
do {
tExecType = aTypeOfExec;
tPrepOp = theFirstOpInList;
while (tPrepOp != NULL) {
bool batch = false;
NdbBlob* tBlob = tPrepOp->theBlobList;
while (tBlob != NULL) {
if (tBlob->preExecute(tExecType, batch) == -1)
return -1;
tBlob = tBlob->theNext;
}
if (batch) {
// blob asked to execute all up to here now
tExecType = NoCommit;
break;
}
tPrepOp = tPrepOp->next();
}
// save rest of prepared ops if batch
NdbOperation* tRestOp;
NdbOperation* tLastOp;
if (tPrepOp != NULL) {
tRestOp = tPrepOp->next();
tPrepOp->next(NULL);
tLastOp = theLastOpInList;
theLastOpInList = tPrepOp;
}
if (tExecType == Commit) {
NdbOperation* tOp = theCompletedFirstOp;
while (tOp != NULL) {
NdbBlob* tBlob = tOp->theBlobList;
while (tBlob != NULL) {
if (tBlob->preCommit() == -1)
return -1;
tBlob = tBlob->theNext;
}
tOp = tOp->next();
}
}
if (executeNoBlobs(tExecType, abortOption, forceSend) == -1)
return -1;
{
NdbOperation* tOp = theCompletedFirstOp;
while (tOp != NULL) {
NdbBlob* tBlob = tOp->theBlobList;
while (tBlob != NULL) {
// may add new operations if batch
if (tBlob->postExecute(tExecType) == -1)
return -1;
tBlob = tBlob->theNext;
}
tOp = tOp->next();
}
}
// add saved prepared ops if batch
if (tPrepOp != NULL && tRestOp != NULL) {
if (theFirstOpInList == NULL)
theFirstOpInList = tRestOp;
else
theLastOpInList->next(tRestOp);
theLastOpInList = tLastOp;
}
} while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
return 0;
}
int
NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
AbortOption abortOption,
int forceSend)
{
//------------------------------------------------------------------------
// We will start by preparing all operations in the transaction defined
......@@ -330,7 +414,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
* Reset error.code on execute
*/
theError.code = 0;
NdbCursorOperation* tcOp = m_theFirstCursorOperation;
if (tcOp != 0){
// Execute any cursor operations
......@@ -885,7 +968,7 @@ Remark: Get an operation from NdbOperation object idlelist and
object, synchronous.
*****************************************************************************/
NdbOperation*
NdbConnection::getNdbOperation(NdbTableImpl * tab)
NdbConnection::getNdbOperation(NdbTableImpl * tab, NdbOperation* aNextOp)
{
NdbOperation* tOp;
......@@ -897,14 +980,28 @@ NdbConnection::getNdbOperation(NdbTableImpl * tab)
tOp = theNdb->getOperation();
if (tOp == NULL)
goto getNdbOp_error1;
if (theLastOpInList != NULL) {
theLastOpInList->next(tOp);
theLastOpInList = tOp;
if (aNextOp == NULL) {
if (theLastOpInList != NULL) {
theLastOpInList->next(tOp);
theLastOpInList = tOp;
} else {
theLastOpInList = tOp;
theFirstOpInList = tOp;
}//if
tOp->next(NULL);
} else {
theLastOpInList = tOp;
theFirstOpInList = tOp;
}//if
tOp->next(NULL);
// add before the given op
if (theFirstOpInList == aNextOp) {
theFirstOpInList = tOp;
} else {
NdbOperation* aLoopOp = theFirstOpInList;
while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
aLoopOp = aLoopOp->next();
assert(aLoopOp != NULL);
aLoopOp->next(tOp);
}
tOp->next(aNextOp);
}
if (tOp->init(tab, this) != -1) {
return tOp;
} else {
......@@ -1068,21 +1165,36 @@ Remark: Get an operation from NdbIndexOperation object idlelist and get
*****************************************************************************/
NdbIndexOperation*
NdbConnection::getNdbIndexOperation(NdbIndexImpl * anIndex,
NdbTableImpl * aTable)
NdbTableImpl * aTable,
NdbOperation* aNextOp)
{
NdbIndexOperation* tOp;
tOp = theNdb->getIndexOperation();
if (tOp == NULL)
goto getNdbOp_error1;
if (theLastOpInList != NULL) {
theLastOpInList->next(tOp);
theLastOpInList = tOp;
if (aNextOp == NULL) {
if (theLastOpInList != NULL) {
theLastOpInList->next(tOp);
theLastOpInList = tOp;
} else {
theLastOpInList = tOp;
theFirstOpInList = tOp;
}//if
tOp->next(NULL);
} else {
theLastOpInList = tOp;
theFirstOpInList = tOp;
}//if
tOp->next(NULL);
// add before the given op
if (theFirstOpInList == aNextOp) {
theFirstOpInList = tOp;
} else {
NdbOperation* aLoopOp = theFirstOpInList;
while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
aLoopOp = aLoopOp->next();
assert(aLoopOp != NULL);
aLoopOp->next(tOp);
}
tOp->next(aNextOp);
}
if (tOp->indxInit(anIndex, aTable, this)!= -1) {
return tOp;
} else {
......
......@@ -273,6 +273,9 @@ NdbDictionary::Table::addColumn(const Column & c){
if(c.getPrimaryKey()){
m_impl.m_noOfKeys++;
}
if (col->getBlobType()) {
m_impl.m_noOfBlobs++;
}
m_impl.buildColumnHash();
}
......
......@@ -34,6 +34,7 @@
#include <AttributeList.hpp>
#include <NdbEventOperation.hpp>
#include "NdbEventOperationImpl.hpp"
#include "NdbBlob.hpp"
#define DEBUG_PRINT 0
#define INCOMPATIBLE_VERSION -2
......@@ -178,7 +179,14 @@ NdbColumnImpl::equal(const NdbColumnImpl& col) const
case NdbDictionary::Column::Double:
case NdbDictionary::Column::Datetime:
case NdbDictionary::Column::Timespec:
break;
case NdbDictionary::Column::Blob:
case NdbDictionary::Column::Clob:
if (m_precision != col.m_precision ||
m_scale != col.m_scale ||
m_length != col.m_length) {
return false;
}
break;
}
if (m_autoIncrement != col.m_autoIncrement){
......@@ -223,6 +231,8 @@ NdbTableImpl::NdbTableImpl()
: NdbDictionary::Table(* this), m_facade(this)
{
m_noOfKeys = 0;
m_sizeOfKeysInWords = 0;
m_noOfBlobs = 0;
m_index = 0;
init();
}
......@@ -257,6 +267,8 @@ NdbTableImpl::init(){
m_indexType = NdbDictionary::Index::Undefined;
m_noOfKeys = 0;
m_sizeOfKeysInWords = 0;
m_noOfBlobs = 0;
}
bool
......@@ -336,6 +348,8 @@ NdbTableImpl::assign(const NdbTableImpl& org)
m_index = org.m_index;
m_noOfKeys = org.m_noOfKeys;
m_sizeOfKeysInWords = org.m_sizeOfKeysInWords;
m_noOfBlobs = org.m_noOfBlobs;
m_version = org.m_version;
m_status = org.m_status;
......@@ -1076,6 +1090,8 @@ columnTypeMapping[] = {
{ DictTabInfo::ExtVarbinary, NdbDictionary::Column::Varbinary },
{ DictTabInfo::ExtDatetime, NdbDictionary::Column::Datetime },
{ DictTabInfo::ExtTimespec, NdbDictionary::Column::Timespec },
{ DictTabInfo::ExtBlob, NdbDictionary::Column::Blob },
{ DictTabInfo::ExtClob, NdbDictionary::Column::Clob },
{ -1, -1 }
};
......@@ -1131,6 +1147,7 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
Uint32 keyInfoPos = 0;
Uint32 keyCount = 0;
Uint32 blobCount;
for(Uint32 i = 0; i < tableDesc.NoOfAttributes; i++) {
DictTabInfo::Attribute attrDesc; attrDesc.init();
......@@ -1187,6 +1204,8 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
} else {
col->m_keyInfoPos = 0;
}
if (col->getBlobType())
blobCount++;
NdbColumnImpl * null = 0;
impl->m_columns.fill(attrDesc.AttributeId, null);
......@@ -1199,6 +1218,8 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
it.next();
}
impl->m_noOfKeys = keyCount;
impl->m_sizeOfKeysInWords = keyInfoPos;
impl->m_noOfBlobs = blobCount;
* ret = impl;
return 0;
}
......@@ -1206,6 +1227,43 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
/*****************************************************************
* Create table and alter table
*/
int
NdbDictionaryImpl::createTable(NdbTableImpl &t)
{
if (m_receiver.createTable(m_ndb, t) != 0)
return -1;
if (t.m_noOfBlobs == 0)
return 0;
// update table def from DICT
NdbTableImpl * tp = getTable(t.m_externalName.c_str());
if (tp == NULL) {
m_error.code = 709;
return -1;
}
if (createBlobTables(* tp) != 0) {
int save_code = m_error.code;
(void)dropTable(t);
m_error.code = save_code;
return -1;
}
return 0;
}
int
NdbDictionaryImpl::createBlobTables(NdbTableImpl &t)
{
for (unsigned i = 0; i < t.m_columns.size(); i++) {
NdbColumnImpl & c = *t.m_columns[i];
if (! c.getBlobType())
continue;
NdbTableImpl bt;
NdbBlob::getBlobTable(bt, &t, &c);
if (createTable(bt) != 0)
return -1;
}
return 0;
}
int
NdbDictInterface::createTable(Ndb & ndb,
NdbTableImpl & impl)
......@@ -1540,6 +1598,12 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl)
if (dropIndex(element.name, name) == -1)
return -1;
}
if (impl.m_noOfBlobs != 0) {
if (dropBlobTables(impl) != 0)
return -1;
}
int ret = m_receiver.dropTable(impl);
if(ret == 0){
const char * internalTableName = impl.m_internalName.c_str();
......@@ -1554,6 +1618,23 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl)
return ret;
}
int
NdbDictionaryImpl::dropBlobTables(NdbTableImpl & t)
{
for (unsigned i = 0; i < t.m_columns.size(); i++) {
NdbColumnImpl & c = *t.m_columns[i];
if (! c.getBlobType())
continue;
char btname[NdbBlob::BlobTableNameSize];
NdbBlob::getBlobTableName(btname, &t, &c);
if (dropTable(btname) != 0) {
if (m_error.code != 709)
return -1;
}
}
return 0;
}
int
NdbDictInterface::dropTable(const NdbTableImpl & impl)
{
......
......@@ -81,6 +81,7 @@ public:
Uint32 m_keyInfoPos;
Uint32 m_extType; // used by restore (kernel type in versin v2x)
bool getInterpretableType() const ;
bool getBlobType() const;
/**
* Equality/assign
......@@ -141,6 +142,8 @@ public:
* Aggregates
*/
Uint32 m_noOfKeys;
unsigned short m_sizeOfKeysInWords;
unsigned short m_noOfBlobs;
/**
* Equality/assign
......@@ -353,13 +356,12 @@ public:
bool setTransporter(class Ndb * ndb, class TransporterFacade * tf);
bool setTransporter(class TransporterFacade * tf);
int createTable(NdbTableImpl &t)
{
return m_receiver.createTable(m_ndb, t);
}
int createTable(NdbTableImpl &t);
int createBlobTables(NdbTableImpl &);
int alterTable(NdbTableImpl &t);
int dropTable(const char * name);
int dropTable(NdbTableImpl &);
int dropBlobTables(NdbTableImpl &);
int invalidateObject(NdbTableImpl &);
int removeCachedObject(NdbTableImpl &);
......@@ -432,6 +434,13 @@ NdbColumnImpl::getInterpretableType() const {
m_type == NdbDictionary::Column::Bigunsigned);
}
inline
bool
NdbColumnImpl::getBlobType() const {
return (m_type == NdbDictionary::Column::Blob ||
m_type == NdbDictionary::Column::Clob);
}
inline
NdbTableImpl &
NdbTableImpl::getImpl(NdbDictionary::Table & t){
......
......@@ -372,6 +372,17 @@ int NdbIndexOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
} else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
(tOpType == ReadExclusive)) {
theStatus = GetValue;
// create blob handles automatically
if (tOpType == DeleteRequest && m_currentTable->m_noOfBlobs != 0) {
for (unsigned i = 0; i < m_currentTable->m_columns.size(); i++) {
NdbColumnImpl* c = m_currentTable->m_columns[i];
assert(c != 0);
if (c->getBlobType()) {
if (getBlobHandle(theNdbCon, c) == NULL)
return -1;
}
}
}
return 0;
} else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
theStatus = SetValue;
......
......@@ -31,6 +31,7 @@
#include "NdbApiSignal.hpp"
#include "NdbRecAttr.hpp"
#include "NdbUtil.hpp"
#include "NdbBlob.hpp"
#include "ndbapi_limits.h"
#include <signaldata/TcKeyReq.hpp>
#include "NdbDictionaryImpl.hpp"
......@@ -103,7 +104,8 @@ NdbOperation::NdbOperation(Ndb* aNdb) :
theFirstSCAN_TABINFO_Recv(NULL),
theLastSCAN_TABINFO_Recv(NULL),
theSCAN_TABCONF_Recv(NULL),
theBoundATTRINFO(NULL)
theBoundATTRINFO(NULL),
theBlobList(NULL)
{
theReceiver.init(NdbReceiver::NDB_OPERATION, this);
theError.code = 0;
......@@ -197,6 +199,7 @@ NdbOperation::init(NdbTableImpl* tab, NdbConnection* myConnection){
theTotalNrOfKeyWordInSignal = 8;
theMagicNumber = 0xABCDEF01;
theBoundATTRINFO = NULL;
theBlobList = NULL;
tSignal = theNdb->getSignal();
if (tSignal == NULL)
......@@ -236,6 +239,8 @@ NdbOperation::release()
NdbCall* tSaveCall;
NdbSubroutine* tSubroutine;
NdbSubroutine* tSaveSubroutine;
NdbBlob* tBlob;
NdbBlob* tSaveBlob;
if (theTCREQ != NULL)
{
......@@ -308,6 +313,14 @@ NdbOperation::release()
}
theBoundATTRINFO = NULL;
}
tBlob = theBlobList;
while (tBlob != NULL)
{
tSaveBlob = tBlob;
tBlob = tBlob->theNext;
theNdb->releaseNdbBlob(tSaveBlob);
}
theBlobList = NULL;
releaseScan();
}
......@@ -356,6 +369,18 @@ NdbOperation::setValue( Uint32 anAttrId,
return setValue(m_currentTable->getColumn(anAttrId), aValuePassed, len);
}
NdbBlob*
NdbOperation::getBlobHandle(const char* anAttrName)
{
return getBlobHandle(theNdbCon, m_currentTable->getColumn(anAttrName));
}
NdbBlob*
NdbOperation::getBlobHandle(Uint32 anAttrId)
{
return getBlobHandle(theNdbCon, m_currentTable->getColumn(anAttrId));
}
int
NdbOperation::incValue(const char* anAttrName, Uint32 aValue)
{
......@@ -428,4 +453,8 @@ NdbOperation::setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len
return setBound(m_accessTable->getColumn(anAttrId), type, aValue, len);
}
const char*
NdbOperation::getTableName() const
{
return m_currentTable->m_externalName.c_str();
}
......@@ -34,6 +34,7 @@
#include "NdbUtil.hpp"
#include "NdbOut.hpp"
#include "NdbImpl.hpp"
#include "NdbBlob.hpp"
#include <Interpreter.hpp>
......@@ -604,6 +605,33 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
return 0;
}//NdbOperation::setValue()
NdbBlob*
NdbOperation::getBlobHandle(NdbConnection* aCon, const NdbColumnImpl* tAttrInfo)
{
NdbBlob* tBlob = theBlobList;
NdbBlob* tLastBlob = NULL;
while (tBlob != NULL) {
if (tBlob->theColumn == tAttrInfo)
return tBlob;
tLastBlob = tBlob;
tBlob = tBlob->theNext;
}
tBlob = theNdb->getNdbBlob();
if (tBlob == NULL)
return NULL;
if (tBlob->atPrepare(aCon, this, tAttrInfo) == -1) {
theNdb->releaseNdbBlob(tBlob);
return NULL;
}
if (tLastBlob == NULL)
theBlobList = tBlob;
else
tLastBlob->theNext = tBlob;
tBlob->theNext = NULL;
theNdbCon->theBlobFlag = true;
return tBlob;
}
/*
* Define bound on index column in range scan.
*/
......
......@@ -569,8 +569,35 @@ NdbOperation::takeOverScanOp(OperationType opType, NdbConnection* updateTrans)
}
}
// create blob handles automatically
if (opType == DeleteRequest && m_currentTable->m_noOfBlobs != 0) {
for (unsigned i = 0; i < m_currentTable->m_columns.size(); i++) {
NdbColumnImpl* c = m_currentTable->m_columns[i];
assert(c != 0);
if (c->getBlobType()) {
if (newOp->getBlobHandle(updateTrans, c) == NULL)
return NULL;
}
}
}
return newOp;
}
int
NdbOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size)
{
const NdbScanReceiver* tScanRec = theNdbCon->thePreviousScanRec;
NdbApiSignal* tSignal = tScanRec->theFirstKEYINFO20_Recv;
unsigned pos = 0;
unsigned n = 0;
while (pos < size) {
if (n == 20) {
tSignal = tSignal->next();
n = 0;
}
const unsigned h = KeyInfo20::HeaderLength;
data[pos++] = tSignal->getDataPtrSend()[h + n++];
}
return 0;
}
......@@ -251,6 +251,17 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
} else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
(tOpType == ReadExclusive)) {
theStatus = GetValue;
// create blob handles automatically
if (tOpType == DeleteRequest && m_currentTable->m_noOfBlobs != 0) {
for (unsigned i = 0; i < m_currentTable->m_columns.size(); i++) {
NdbColumnImpl* c = m_currentTable->m_columns[i];
assert(c != 0);
if (c->getBlobType()) {
if (getBlobHandle(theNdbCon, c) == NULL)
return -1;
}
}
}
return 0;
} else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
theStatus = SetValue;
......@@ -497,3 +508,24 @@ LastWordLabel:
return 0;
}
int
NdbOperation::getKeyFromTCREQ(Uint32* data, unsigned size)
{
assert(m_accessTable != 0 && m_accessTable->m_sizeOfKeysInWords != 0);
assert(m_accessTable->m_sizeOfKeysInWords == size);
unsigned pos = 0;
while (pos < 8 && pos < size) {
data[pos++] = theKEYINFOptr[pos];
}
NdbApiSignal* tSignal = theFirstKEYINFO;
unsigned n = 0;
while (pos < size) {
if (n == 20) {
tSignal = tSignal->next();
n = 0;
}
data[pos++] = tSignal->getDataPtrSend()[3 + n++];
}
return 0;
}
......@@ -34,6 +34,7 @@
#include "NdbApiSignal.hpp"
#include <NdbOut.hpp>
#include "NdbDictionaryImpl.hpp"
#include "NdbBlob.hpp"
NdbScanOperation::NdbScanOperation(Ndb* aNdb) :
NdbCursorOperation(aNdb),
......@@ -294,6 +295,18 @@ int NdbScanOperation::setValue(Uint32 anAttrId, double aValue)
return 0;
}
NdbBlob*
NdbScanOperation::getBlobHandle(const char* anAttrName)
{
return NdbOperation::getBlobHandle(m_transConnection, m_currentTable->getColumn(anAttrName));
}
NdbBlob*
NdbScanOperation::getBlobHandle(Uint32 anAttrId)
{
return NdbOperation::getBlobHandle(m_transConnection, m_currentTable->getColumn(anAttrId));
}
// Private methods
int NdbScanOperation::executeCursor(int ProcessorId)
......@@ -344,6 +357,15 @@ int NdbScanOperation::nextResult(bool fetchAllowed)
const NdbError err = theNdbCon->getNdbError();
m_transConnection->setOperationErrorCode(err.code);
}
if (result == 0) {
// handle blobs
NdbBlob* tBlob = theBlobList;
while (tBlob != NULL) {
if (tBlob->atNextResult() == -1)
return -1;
tBlob = tBlob->theNext;
}
}
return result;
}
......
......@@ -20,6 +20,7 @@
#include "NdbDictionaryImpl.hpp"
#include <NdbOperation.hpp>
#include <NdbConnection.hpp>
#include <NdbBlob.hpp>
static void
......@@ -65,3 +66,10 @@ NdbOperation::getNdbError() const {
update(theError);
return theError;
}
const
NdbError &
NdbBlob::getNdbError() const {
update(theError);
return theError;
}
......@@ -85,6 +85,7 @@ Ndb::Ndb( const char* aDataBase , const char* aDataBaseSchema) :
theSubroutineList(NULL),
theCallList(NULL),
theScanList(NULL),
theNdbBlobIdleList(NULL),
theNoOfDBnodes(0),
theDBnodes(NULL),
the_release_ind(NULL),
......@@ -235,6 +236,8 @@ Ndb::~Ndb()
freeNdbCall();
while (theScanList != NULL)
freeNdbScanRec();
while (theNdbBlobIdleList != NULL)
freeNdbBlob();
releaseTransactionArrays();
startTransactionNodeSelectionData.release();
......
......@@ -27,6 +27,7 @@
#include "NdbScanReceiver.hpp"
#include "NdbUtil.hpp"
#include "API.hpp"
#include "NdbBlob.hpp"
void
Ndb::checkFailedNode()
......@@ -435,6 +436,19 @@ Ndb::getSignal()
return tSignal;
}
NdbBlob*
Ndb::getNdbBlob()
{
NdbBlob* tBlob = theNdbBlobIdleList;
if (tBlob != NULL) {
theNdbBlobIdleList = tBlob->theNext;
tBlob->init();
} else {
tBlob = new NdbBlob;
}
return tBlob;
}
/***************************************************************************
void releaseNdbBranch(NdbBranch* aNdbBranch);
......@@ -601,6 +615,14 @@ Ndb::releaseSignalsInList(NdbApiSignal** pList){
}
}
void
Ndb::releaseNdbBlob(NdbBlob* aBlob)
{
aBlob->release();
aBlob->theNext = theNdbBlobIdleList;
theNdbBlobIdleList = aBlob;
}
/***************************************************************************
void freeOperation();
......@@ -745,6 +767,14 @@ Ndb::freeSignal()
cfreeSignals++;
}
void
Ndb::freeNdbBlob()
{
NdbBlob* tBlob = theNdbBlobIdleList;
theNdbBlobIdleList = tBlob->theNext;
delete tBlob;
}
/****************************************************************************
int releaseConnectToNdb(NdbConnection* aConnectConnection);
......
......@@ -418,8 +418,14 @@ ErrorBundle ErrorCodes[] = {
{ 4259, AE, "Invalid set of range scan bounds" },
{ 4260, UD, "NdbScanFilter: Operator is not defined in NdbScanFilter::Group"},
{ 4261, UD, "NdbScanFilter: Column is NULL"},
{ 4262, UD, "NdbScanFilter: Condition is out of bounds"}
{ 4262, UD, "NdbScanFilter: Condition is out of bounds"},
{ 4263, IE, "Invalid blob attributes or invalid blob parts table" },
{ 4264, AE, "Invalid usage of blob attribute" },
{ 4265, AE, "Method is not valid in current blob state" },
{ 4266, AE, "Invalid blob seek position" },
{ 4267, IE, "Corrupted blob value" },
{ 4268, IE, "Error in blob head update forced rollback of transaction" },
{ 4268, IE, "Unknown blob error" }
};
static
......
......@@ -88,6 +88,7 @@ struct PhysAttr { int storage; int logging; };
struct PhysAttr* m_phys_attr;
NdbDictionary::Object::FragmentType m_storage_attr;
bool m_logging_attr;
SqlType::Type m_sql_type;
}
/* keywords */
......@@ -100,6 +101,7 @@ struct PhysAttr { int storage; int logging; };
T_BLOB
T_BY
T_CHAR
T_CLOB
T_CONSTRAINT
T_CREATE
T_DATETIME
......@@ -128,6 +130,7 @@ struct PhysAttr { int storage; int logging; };
T_LIMIT
T_LOGGING
T_LONGBLOB
T_LONGCLOB
T_MEDIUM
T_NOLOGGING
T_NOT
......@@ -248,6 +251,7 @@ struct PhysAttr { int storage; int logging; };
%type <m_phys_attr> phys_attr2
%type <m_storage_attr> storage_attr
%type <m_logging_attr> logging_attr
%type <m_sql_type> blob_type
%%
......@@ -606,10 +610,10 @@ data_type:
$$ = dataType;
}
|
blob_keyword
blob_type
{
Plan_root* root = simpleParser.root();
SqlType sqlType(SqlType::Blob, true);
SqlType sqlType($1, true);
Plan_data_type* dataType = new Plan_data_type(root, sqlType);
root->saveNode(dataType);
$$ = dataType;
......@@ -620,10 +624,26 @@ dummy_binary:
|
T_BINARY
;
blob_keyword:
blob_type:
T_BLOB
{
$$ = SqlType::Blob;
}
|
T_LONGBLOB
{
$$ = SqlType::Blob;
}
|
T_CLOB
{
$$ = SqlType::Clob;
}
|
T_LONGCLOB
{
$$ = SqlType::Clob;
}
;
create_column_rest:
/* empty */
......
......@@ -149,6 +149,7 @@ static const SqlKeyword sqlKeyword[] = {
{ "BLOB", T_BLOB, StateType },
{ "BY", T_BY, -1 },
{ "CHAR", T_CHAR, StateType },
{ "CLOB", T_CLOB, StateType },
{ "CONSTRAINT", T_CONSTRAINT, -1 },
{ "CREATE", T_CREATE, -1 },
{ "DATETIME", T_DATETIME, StateType },
......@@ -177,6 +178,7 @@ static const SqlKeyword sqlKeyword[] = {
{ "LIMIT", T_LIMIT, -1 },
{ "LOGGING", T_LOGGING, StatePhys },
{ "LONGBLOB", T_LONGBLOB, StateType },
{ "LONGCLOB", T_LONGCLOB, StateType },
{ "MEDIUM", T_MEDIUM, StatePhys },
{ "NOLOGGING", T_NOLOGGING, StatePhys },
{ "NOT", T_NOT, -1 },
......
......@@ -78,6 +78,9 @@ SqlType::setType(Ctx& ctx, Type type, bool nullable)
case Blob:
setType(ctx, Varbinary, FAKE_BLOB_SIZE, nullable); // XXX BLOB hack
return;
case Clob:
setType(ctx, Varchar, FAKE_BLOB_SIZE, nullable); // XXX BLOB hack
return;
case Null:
case Unbound:
break;
......@@ -193,6 +196,9 @@ SqlType::setType(Ctx& ctx, const NdbDictionary::Column* ndbColumn)
case NdbDictionary::Column::Blob:
setType(ctx, Blob, nullable);
return;
case NdbDictionary::Column::Clob:
setType(ctx, Clob, nullable);
return;
default:
break;
}
......
......@@ -74,6 +74,7 @@ public:
Date = SQL_DATE,
Datetime = SQL_TYPE_TIMESTAMP,
Blob = SQL_BLOB,
Clob = SQL_CLOB,
Null = NullDataType, // not an ODBC SQL type
Unbound = UnboundDataType // special for placeholders
};
......
......@@ -14,6 +14,7 @@ flexTT \
testBackup \
testBasic \
testBasicAsynch \
testBlobs \
testDataBuffers \
testDict \
testIndex \
......@@ -47,7 +48,7 @@ flexTT_SOURCES = flexTT.cpp
testBackup_SOURCES = testBackup.cpp
testBasic_SOURCES = testBasic.cpp
testBasicAsynch_SOURCES = testBasicAsynch.cpp
#testBlobs_SOURCES = testBlobs.cpp
testBlobs_SOURCES = testBlobs.cpp
testDataBuffers_SOURCES = testDataBuffers.cpp
testDict_SOURCES = testDict.cpp
testIndex_SOURCES = testIndex.cpp
......@@ -77,3 +78,4 @@ testBackup_LDADD = $(LDADD) bank/libbank.a
# Don't update the files from bitkeeper
%::SCCS/s.%
......@@ -37,7 +37,8 @@ BIN_DIRS = \
indexTest \
test_event \
indexTest2 \
testGrep
testGrep \
testBlobs
ifeq ($(NDB_OS), SOLARIS)
ifeq ($(NDB_COMPILER), FORTE6)
......
This diff is collapsed.
run-test/README
This document describes how atrt works and how to use it.
atrt is a test program driver.
atrt supports fully distributed test and utilizes ndb_cpcd.
=================================
atrt has the following main loop:
/**
* Psuedo code for atrt
*/
read config file (default d.txt)
contact each ndb_cpcd
start each ndb_mgmd
connect to each ndb_mgmd
for each read(test case)
do
if previous test failed (or is first test)
stop each ndbd
start each ndbd
wait for ndbd to get started
start each mysqld
start each test prg
wait while all is running and max time not elapsed
stop each mysqld
stop each test prg
gather result
done
/**
* End of psuedo code
*/
=================================
File added
This diff is collapsed.
......@@ -30,35 +30,6 @@
#include <mgmapi.h>
#include "CpcClient.hpp"
/**
psuedo code for run-test.bin
define autotest_wrapper process at each host
start ndb-processes
for each testcase
do
start mysqld processes
start replication processes
start test programs
wait until test program finished or max time passed
stop test program
stop replication processes
stop mysqld processes
write report data-file
if test failed and ! last test
restart ndb processes
drop all tables created by test
done
stop ndb processes
undefined wrapper processes
*/
/** Global variables */
static const char progname[] = "ndb_atrt";
static const char * g_gather_progname = "atrt-gather-result.sh";
......@@ -75,6 +46,7 @@ static const char * g_report_filename = 0;
static const char * g_default_user = 0;
static const char * g_default_base_dir = 0;
static int g_default_base_port = 0;
static int g_mysqld_use_base = 1;
static int g_report = 0;
static int g_verbosity = 0;
......@@ -385,6 +357,7 @@ setup_config(atrt_config& config){
int lineno = 0;
char buf[2048];
BaseString connect_string;
int mysql_port_offset = 0;
while(fgets(buf, 2048, f)){
lineno++;
......@@ -416,6 +389,11 @@ setup_config(atrt_config& config){
continue;
}
if(split1[0].trim() == "mysqld-use-base" && split1[1].trim() == "no"){
g_mysqld_use_base = 0;
continue;
}
Vector<BaseString> hosts;
if(split1[1].trim().split(hosts) <= 0){
g_logger.warning("Invalid line %d in %s - ignoring",
......@@ -490,6 +468,21 @@ setup_config(atrt_config& config){
proc.m_proc.m_path.assign(dir).append("/libexec/ndbd");
proc.m_proc.m_args = "-i -n";
proc.m_proc.m_cwd.appfmt("%d.ndbd", index);
} else if(split1[0] == "mysqld"){
proc.m_type = atrt_process::MYSQL_SERVER;
proc.m_proc.m_name.assfmt("%d-%s", index, "mysqld");
proc.m_proc.m_path.assign(dir).append("/libexec/mysqld");
proc.m_proc.m_args = "--core-file --ndbcluster";
proc.m_proc.m_cwd.appfmt("%d.mysqld", index);
if(mysql_port_offset > 0 || g_mysqld_use_base){
// setup mysql specific stuff
const char * basedir = proc.m_proc.m_cwd.c_str();
proc.m_proc.m_args.appfmt("--datadir=%s", basedir);
proc.m_proc.m_args.appfmt("--pid-file=%s/mysql.pid", basedir);
proc.m_proc.m_args.appfmt("--socket=%s/mysql.sock", basedir);
proc.m_proc.m_args.appfmt("--port=%d",
g_default_base_port-(++mysql_port_offset));
}
} else if(split1[0] == "api"){
proc.m_type = atrt_process::NDB_API;
proc.m_proc.m_name.assfmt("%d-%s", index, "ndb_api");
......@@ -714,7 +707,7 @@ bool
start_processes(atrt_config& config, int types){
for(size_t i = 0; i<config.m_processes.size(); i++){
atrt_process & proc = config.m_processes[i];
if((types & proc.m_type) != 0){
if((types & proc.m_type) != 0 && proc.m_proc.m_path != ""){
if(!start_process(proc)){
return false;
}
......@@ -782,18 +775,24 @@ update_status(atrt_config& config, int){
for(size_t i = 0; i<config.m_processes.size(); i++){
atrt_process & proc = config.m_processes[i];
Vector<SimpleCpcClient::Process> & h_procs = m_procs[proc.m_host->m_index];
bool found = false;
for(size_t j = 0; j<h_procs.size(); j++){
if(proc.m_proc.m_id == h_procs[j].m_id){
found = true;
proc.m_proc.m_status = h_procs[j].m_status;
break;
if(proc.m_proc.m_id != -1){
Vector<SimpleCpcClient::Process> &h_procs= m_procs[proc.m_host->m_index];
bool found = false;
for(size_t j = 0; j<h_procs.size(); j++){
if(proc.m_proc.m_id == h_procs[j].m_id){
found = true;
proc.m_proc.m_status = h_procs[j].m_status;
break;
}
}
if(!found){
g_logger.error("update_status: not found");
g_logger.error("id: %d host: %s cmd: %s",
proc.m_proc.m_id,
proc.m_hostname.c_str(),
proc.m_proc.m_path.c_str());
return false;
}
}
if(!found){
g_logger.error("update_status: not found");
return false;
}
}
return true;
......@@ -900,16 +899,24 @@ setup_test_case(atrt_config& config, const atrt_testcase& tc){
return false;
}
for(size_t i = 0; i<config.m_processes.size(); i++){
size_t i = 0;
for(; i<config.m_processes.size(); i++){
atrt_process & proc = config.m_processes[i];
if(proc.m_type == atrt_process::NDB_API){
proc.m_proc.m_path.assign(proc.m_host->m_base_dir).append("/bin/").append(tc.m_command);
proc.m_proc.m_path.assfmt("%s/bin/%s", proc.m_host->m_base_dir.c_str(),
tc.m_command.c_str());
proc.m_proc.m_args.assign(tc.m_args);
return true;
break;
}
}
return false;
for(i++; i<config.m_processes.size(); i++){
atrt_process & proc = config.m_processes[i];
if(proc.m_type == atrt_process::NDB_API){
proc.m_proc.m_path.assign("");
proc.m_proc.m_args.assign("");
}
}
return true;
}
bool
......
......@@ -33,6 +33,12 @@
#include <ctype.h>
#include <wctype.h>
#ifndef SQL_BLOB
#define SQL_BLOB 30
#endif
#ifndef SQL_CLOB
#define SQL_CLOB 40
#endif
/**************************************************************************
* ------------------------------------------------------------------------
......@@ -211,8 +217,10 @@ SQLINTEGER display_length(SQLSMALLINT coltype, SQLINTEGER collen,
switch (coltype) {
case SQL_VARCHAR:
case SQL_CHAR:
//case SQL_BLOB:
//case SQL_CLOB:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_BLOB:
case SQL_CLOB:
case SQL_BIT:
//case SQL_REF:
//case SQL_BIT_VARYING:
......
......@@ -950,17 +950,10 @@ String *Item_func_left::val_str(String *str)
return 0;
if (length <= 0)
return &my_empty_string;
length= res->charpos(length);
if (res->length() > (ulong) length)
{ // Safe even if const arg
if (!res->alloced_length())
{ // Don't change const str
str_value= *res; // Not malloced string
res= &str_value;
}
res->length((uint) length);
}
return res;
if (res->length() <= (uint) length)
return res;
str_value.set(*res, 0, res->charpos(length));
return &str_value;
}
......
......@@ -1685,6 +1685,9 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2;
char *record= (char*) item->table->record[0];
if (item->result.length())
item->result.append(*item->separator);
tmp.length(0);
for (uint i= 0; i < item->arg_count_field; i++)
......@@ -1714,14 +1717,6 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
item->result.append(*res);
}
}
if (item->tree_mode) // Last item of tree
{
item->show_elements++;
if (item->show_elements < item->tree->elements_in_tree)
item->result.append(*item->separator);
}
else
item->result.append(*item->separator);
/* stop if length of result more than group_concat_max_len */
if (item->result.length() > item->group_concat_max_len)
......@@ -1752,7 +1747,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
tree_mode(0), distinct(is_distinct), warning_for_row(0),
separator(is_separator), tree(&tree_base), table(0),
order(0), tables_list(0),
show_elements(0), arg_count_order(0), arg_count_field(0),
arg_count_order(0), arg_count_field(0),
count_cut_values(0)
{
Item *item_select;
......@@ -1818,7 +1813,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
order(item->order),
tables_list(item->tables_list),
group_concat_max_len(item->group_concat_max_len),
show_elements(item->show_elements),
arg_count_order(item->arg_count_order),
arg_count_field(item->arg_count_field),
field_list_offset(item->field_list_offset),
......@@ -2126,15 +2120,9 @@ String* Item_func_group_concat::val_str(String* str)
return 0;
if (tree_mode)
{
show_elements= 0;
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
left_root_right);
}
else
{
if (!warning_for_row)
result.length(result.length()-separator->length());
}
if (count_cut_values && !warning_available)
{
warning_available= TRUE;
......
......@@ -696,7 +696,6 @@ class Item_func_group_concat : public Item_sum
ORDER **order;
TABLE_LIST *tables_list;
ulong group_concat_max_len;
uint show_elements;
uint arg_count_order;
uint arg_count_field;
uint field_list_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment