diff options
Diffstat (limited to 'ndb/src/ndbapi')
36 files changed, 2358 insertions, 775 deletions
diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp index 1b536b6d741..b26d550fe31 100644 --- a/ndb/src/ndbapi/ClusterMgr.cpp +++ b/ndb/src/ndbapi/ClusterMgr.cpp @@ -21,7 +21,6 @@ #include "TransporterFacade.hpp" #include "ClusterMgr.hpp" #include <IPCConfig.hpp> -#include "AttrType.hpp" #include "NdbApiSignal.hpp" #include "API.hpp" #include <NdbSleep.h> @@ -33,6 +32,10 @@ #include <signaldata/NFCompleteRep.hpp> #include <signaldata/ApiRegSignalData.hpp> +#include <mgmapi.h> +#include <mgmapi_configuration.hpp> +#include <mgmapi_config_parameters.h> + // Just a C wrapper for threadMain extern "C" void* @@ -70,32 +73,49 @@ ClusterMgr::~ClusterMgr(){ } void -ClusterMgr::init(const IPCConfig & config){ - NodeId tmp = 0; - while(config.getNextRemoteNodeId(tmp)) { +ClusterMgr::init(ndb_mgm_configuration_iterator & iter){ + for(iter.first(); iter.valid(); iter.next()){ + Uint32 tmp = 0; + if(iter.get(CFG_NODE_ID, &tmp)) + continue; + theNodes[tmp].defined = true; #if 0 ndbout << "--------------------------------------" << endl; - config.print(); ndbout << "--------------------------------------" << endl; ndbout_c("ClusterMgr: Node %d defined as %s", tmp, config.getNodeType(tmp)); #endif - if(strcmp(config.getNodeType(tmp), "DB") == 0) { + + unsigned type; + if(iter.get(CFG_TYPE_OF_SECTION, &type)) + continue; + + switch(type){ + case NODE_TYPE_DB: theNodes[tmp].m_info.m_type = NodeInfo::DB; - } else if(strcmp(config.getNodeType(tmp), "API") == 0) { + break; + case NODE_TYPE_API: theNodes[tmp].m_info.m_type = NodeInfo::API; - } else if(strcmp(config.getNodeType(tmp), "MGM") == 0) { + break; + case NODE_TYPE_MGM: theNodes[tmp].m_info.m_type = NodeInfo::MGM; - } else if(strcmp(config.getNodeType(tmp), "REP") == 0) { + break; + case NODE_TYPE_REP: theNodes[tmp].m_info.m_type = NodeInfo::REP; - } else if(strcmp(config.getNodeType(tmp), "EXTERNAL REP") == 0) { + break; + case NODE_TYPE_EXT_REP: theNodes[tmp].m_info.m_type = NodeInfo::REP; - theNodes[tmp].hbFrequency = config.getREPHBFrequency(tmp); - assert(100 <= theNodes[tmp].hbFrequency && - theNodes[tmp].hbFrequency < 60 * 60 * 1000); - } else { + { + Uint32 hbFreq = 10000; + //ndb_mgm_get_int_parameter(iter, CFG_, &hbFreq); + theNodes[tmp].hbFrequency = hbFreq; + assert(100 <= hbFreq && hbFreq < 60 * 60 * 1000); + } + break; + default: + type = type; #if 0 - ndbout_c("ClusterMgr: Unknown node type: %s", config.getNodeType(tmp)); + ndbout_c("ClusterMgr: Unknown node type: %d", type); #endif } } @@ -163,45 +183,43 @@ ClusterMgr::threadMain( ){ const NodeId nodeId = i; Node & theNode = theNodes[nodeId]; - if (theNode.defined == true) { -#if 0 - ndbout_c("ClusterMgr: compatible %d", (int)nodeId); -#endif + if (!theNode.defined) + continue; - if (theNode.connected == false){ - theFacade.doConnect(nodeId); - continue; + if (theNode.connected == false){ + theFacade.doConnect(nodeId); + continue; + } + + if (!theNode.compatible){ + continue; + } + + theNode.hbCounter += timeSlept; + if (theNode.hbCounter >= theNode.hbFrequency){ + /** + * It is now time to send a new Heartbeat + */ + theNode.hbSent++; + theNode.hbCounter = 0; + /** + * If the node is of type REP, + * then the receiver of the signal should be API_CLUSTERMGR + */ + if (theNode.m_info.m_type == NodeInfo::REP) { + signal.theReceiversBlockNumber = API_CLUSTERMGR; } - -#if 0 - ndbout_c("ClusterMgr: connected %d", (int)nodeId); +#if 0 + ndbout_c("ClusterMgr: Sending API_REGREQ to node %d", (int)nodeId); #endif - - theNode.hbCounter += timeSlept; - if (theNode.hbCounter >= theNode.hbFrequency){ - /** - * It is now time to send a new Heartbeat - */ - theNode.hbSent++; - theNode.hbCounter = 0; - /** - * If the node is of type REP, - * then the receiver of the signal should be API_CLUSTERMGR - */ - if (theNode.m_info.m_type == NodeInfo::REP) { - signal.theReceiversBlockNumber = API_CLUSTERMGR; - } -#if 0 - ndbout_c("ClusterMgr: Sending API_REGREQ to node %d", (int)nodeId); -#endif - theFacade.sendSignalUnCond(&signal, nodeId); - }//if - - if (theNode.hbSent == 4 && theNode.hbFrequency > 0){ - reportNodeFailed(i); - }//if - }//if(defined) - }//for + theFacade.sendSignalUnCond(&signal, nodeId); + }//if + + if (theNode.hbSent == 4 && theNode.hbFrequency > 0){ + reportNodeFailed(i); + }//if + } + /** * End of secure area. Let other threads in */ @@ -282,6 +300,10 @@ ClusterMgr::execAPI_REGCONF(const Uint32 * theData){ const ApiRegConf * const apiRegConf = (ApiRegConf *)&theData[0]; const NodeId nodeId = refToNode(apiRegConf->qmgrRef); +#if 0 + ndbout_c("ClusterMgr: Recd API_REGCONF from node %d", nodeId); +#endif + assert(nodeId > 0 && nodeId < MAX_NODES); Node & node = theNodes[nodeId]; diff --git a/ndb/src/ndbapi/ClusterMgr.hpp b/ndb/src/ndbapi/ClusterMgr.hpp index 7b7b947742b..cc3cf66c8aa 100644 --- a/ndb/src/ndbapi/ClusterMgr.hpp +++ b/ndb/src/ndbapi/ClusterMgr.hpp @@ -40,7 +40,7 @@ class ClusterMgr { public: ClusterMgr(class TransporterFacade &); ~ClusterMgr(); - void init(const IPCConfig & config); + void init(struct ndb_mgm_configuration_iterator & config); void reportConnected(NodeId nodeId); void reportDisconnected(NodeId nodeId); @@ -114,7 +114,7 @@ ClusterMgr::getNoOfConnectedNodes() const { return noOfConnectedNodes; } -/******************************************************************************/ +/*****************************************************************************/ /** * @class ArbitMgr diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp index e59793bbc09..098acc9006a 100644 --- a/ndb/src/ndbapi/DictCache.hpp +++ b/ndb/src/ndbapi/DictCache.hpp @@ -56,13 +56,14 @@ public: NdbTableImpl* put(const char * name, NdbTableImpl *); void drop(NdbTableImpl *); void release(NdbTableImpl *); -private: +public: enum Status { OK = 0, DROPPED = 1, RETREIVING = 2 }; +private: struct TableVersion { Uint32 m_version; Uint32 m_refCount; diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am new file mode 100644 index 00000000000..2ec58ab6e85 --- /dev/null +++ b/ndb/src/ndbapi/Makefile.am @@ -0,0 +1,50 @@ +#SUBDIRS = signal-sender + +noinst_LTLIBRARIES = libndbapi.la + +libndbapi_la_SOURCES = \ + TransporterFacade.cpp \ + ClusterMgr.cpp \ + Ndb.cpp \ + NdbPoolImpl.cpp \ + NdbPool.cpp \ + Ndblist.cpp \ + Ndbif.cpp \ + Ndbinit.cpp \ + Ndberr.cpp \ + ndberror.c \ + NdbErrorOut.cpp \ + NdbConnection.cpp \ + NdbConnectionScan.cpp \ + NdbOperation.cpp \ + NdbOperationSearch.cpp \ + NdbOperationScan.cpp \ + NdbOperationInt.cpp \ + NdbOperationDefine.cpp \ + NdbOperationExec.cpp \ + NdbResultSet.cpp \ + NdbCursorOperation.cpp \ + NdbScanReceiver.cpp NdbScanOperation.cpp \ + NdbScanFilter.cpp \ + NdbIndexOperation.cpp \ + NdbEventOperation.cpp \ + NdbEventOperationImpl.cpp \ + NdbApiSignal.cpp \ + NdbRecAttr.cpp \ + NdbUtil.cpp \ + NdbReceiver.cpp \ + NdbDictionary.cpp \ + NdbDictionaryImpl.cpp \ + DictCache.cpp \ + NdbBlob.cpp + +INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi + +# Ndbapi cannot handle -O3 +NDB_CXXFLAGS_RELEASE_LOC = -O2 + +include $(top_srcdir)/ndb/config/common.mk.am +include $(top_srcdir)/ndb/config/type_ndbapi.mk.am + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/ndb/src/ndbapi/Makefile b/ndb/src/ndbapi/Makefile_old index f4c82e5d6ba..c2bb0189a7f 100644 --- a/ndb/src/ndbapi/Makefile +++ b/ndb/src/ndbapi/Makefile_old @@ -15,13 +15,16 @@ LIB_TARGET_ARCHIVES := $(ARCHIVE_TARGET) \ transporter \ general \ signaldataprint \ - mgmsrvcommon \ + mgmapi mgmsrvcommon \ portlib \ logger \ trace DIRS := signal-sender +CFLAGS_TransporterFacade.cpp := -I$(call fixpath,$(NDB_TOP)/src/mgmapi) +CFLAGS_ClusterMgr.cpp := -I$(call fixpath,$(NDB_TOP)/src/mgmapi) + # Source files of non-templated classes (.cpp files) SOURCES = \ TransporterFacade.cpp \ @@ -55,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 diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 448a29ca485..fe7260c4693 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -26,8 +26,6 @@ Name: Ndb.cpp #include "NdbApiSignal.hpp" #include "NdbImpl.hpp" -#include "NdbSchemaOp.hpp" -#include "NdbSchemaCon.hpp" #include <NdbOperation.hpp> #include <NdbConnection.hpp> #include <NdbEventOperation.hpp> @@ -40,8 +38,6 @@ Name: Ndb.cpp #include <NdbEnv.h> #include <BaseString.hpp> -static bool fullyQualifiedNames = true; - /**************************************************************************** void connect(); @@ -155,7 +151,7 @@ Ndb::NDB_connect(Uint32 tNode) // Set connection pointer as NdbConnection object //************************************************ tSignal->setData(theMyRef, 2); // Set my block reference - tNdbCon->Status(Connecting); // Set status to connecting + tNdbCon->Status(NdbConnection::Connecting); // Set status to connecting Uint32 nodeSequence; { // send and receive signal tp->lock_mutex(); @@ -178,7 +174,7 @@ Ndb::NDB_connect(Uint32 tNode) }//if } - if ((tReturnCode == 0) && (tNdbCon->Status() == Connected)) { + if ((tReturnCode == 0) && (tNdbCon->Status() == NdbConnection::Connected)) { //************************************************ // Send and receive was successful //************************************************ @@ -434,7 +430,7 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId) theFirstTransId = tFirstTransId + 1; }//if #ifdef VM_TRACE - if (tConnection->theListState != NotInList) { + if (tConnection->theListState != NdbConnection::NotInList) { printState("startTransactionLocal %x", tConnection); abort(); } @@ -476,6 +472,19 @@ Ndb::closeTransaction(NdbConnection* aConnection) //----------------------------------------------------- // closeTransaction called on non-existing transaction //----------------------------------------------------- + + if(aConnection->theError.code == 4008){ + /** + * When a SCAN timed-out, returning the NdbConnection leads + * to reuse. And TC crashes when the API tries to reuse it to + * something else... + */ +#ifdef VM_TRACE + printf("Scan timeout:ed NdbConnection-> not returning it-> memory leak\n"); +#endif + return; + } + #ifdef VM_TRACE printf("Non-existing transaction into closeTransaction\n"); abort(); @@ -589,7 +598,7 @@ Ndb::NdbTamper(TamperType aAction, int aNode) tSignal.setData (tAction, 1); tSignal.setData(tNdbConn->ptr2int(),2); tSignal.setData(theMyRef,3); // Set return block reference - tNdbConn->Status(Connecting); // Set status to connecting + tNdbConn->Status(NdbConnection::Connecting); // Set status to connecting TransporterFacade *tp = TransporterFacade::instance(); if (tAction == 3) { tp->lock_mutex(); @@ -622,7 +631,7 @@ Ndb::NdbTamper(TamperType aAction, int aNode) }//if ret_code = sendRecSignal(tNode, WAIT_NDB_TAMPER, &tSignal, 0); if (ret_code == 0) { - if (tNdbConn->Status() != Connected) { + if (tNdbConn->Status() != NdbConnection::Connected) { theRestartGCI = 0; }//if releaseNdbCon(tNdbConn); @@ -637,6 +646,7 @@ Ndb::NdbTamper(TamperType aAction, int aNode) return 0; #endif } +#if 0 /**************************************************************************** NdbSchemaCon* startSchemaTransaction(); @@ -678,7 +688,7 @@ Ndb::closeSchemaTransaction(NdbSchemaCon* aSchemaCon) theSchemaConToNdbList = NULL; return; }//Ndb::closeSchemaTransaction() - +#endif /***************************************************************************** void RestartGCI(int aRestartGCI); @@ -826,7 +836,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) tOperation->interpretedUpdateTuple(); tOperation->equal("SYSKEY_0", aTableId ); { -#ifdef NDB_SOLARIS +#ifdef WORDS_BIGENDIAN Uint64 cacheSize64 = opValue; // XXX interpreter bug on Uint32 tOperation->incValue("NEXTID", cacheSize64); #else @@ -992,7 +1002,7 @@ Ndb::StartTransactionNodeSelectionData::release(){ Uint32 convertEndian(Uint32 Data) { -#ifdef _BIG_ENDIAN +#ifdef WORDS_BIGENDIAN Uint32 t1, t2, t3, t4; t4 = (Data >> 24) & 255; t3 = (Data >> 16) & 255; @@ -1014,18 +1024,14 @@ const char * Ndb::getCatalogName() const void Ndb::setCatalogName(const char * a_catalog_name) { if (a_catalog_name) { - strncpy(theDataBase, a_catalog_name, NDB_MAX_DATABASE_NAME_SIZE); - // Prepare prefix for faster operations - uint db_len = MIN(strlen(theDataBase), NDB_MAX_DATABASE_NAME_SIZE - 1); - uint schema_len = - MIN(strlen(theDataBaseSchema), NDB_MAX_SCHEMA_NAME_SIZE - 1); - strncpy(prefixName, theDataBase, NDB_MAX_DATABASE_NAME_SIZE - 1); - prefixName[db_len] = '/'; - strncpy(prefixName+db_len+1, theDataBaseSchema, - NDB_MAX_SCHEMA_NAME_SIZE - 1); - prefixName[db_len+schema_len+1] = '/'; - prefixName[db_len+schema_len+2] = '\0'; - prefixEnd = prefixName + db_len+schema_len + 2; + snprintf(theDataBase, sizeof(theDataBase), "%s", + a_catalog_name ? a_catalog_name : ""); + + int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + theDataBase, table_name_separator, + theDataBaseSchema, table_name_separator); + prefixEnd = prefixName + (len < sizeof(prefixName) ? len : + sizeof(prefixName) - 1); } } @@ -1037,18 +1043,14 @@ const char * Ndb::getSchemaName() const void Ndb::setSchemaName(const char * a_schema_name) { if (a_schema_name) { - strncpy(theDataBaseSchema, a_schema_name, NDB_MAX_SCHEMA_NAME_SIZE); - // Prepare prefix for faster operations - uint db_len = MIN(strlen(theDataBase), NDB_MAX_DATABASE_NAME_SIZE - 1); - uint schema_len = - MIN(strlen(theDataBaseSchema), NDB_MAX_SCHEMA_NAME_SIZE - 1); - strncpy(prefixName, theDataBase, NDB_MAX_DATABASE_NAME_SIZE - 1); - prefixName[db_len] = '/'; - strncpy(prefixName+db_len+1, theDataBaseSchema, - NDB_MAX_SCHEMA_NAME_SIZE - 1); - prefixName[db_len+schema_len+1] = '/'; - prefixName[db_len+schema_len+2] = '\0'; - prefixEnd = prefixName + db_len+schema_len + 2; + snprintf(theDataBaseSchema, sizeof(theDataBase), "%s", + a_schema_name ? a_schema_name : ""); + + int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + theDataBase, table_name_separator, + theDataBaseSchema, table_name_separator); + prefixEnd = prefixName + (len < sizeof(prefixName) ? len : + sizeof(prefixName) - 1); } } @@ -1086,43 +1088,36 @@ bool Ndb::usingFullyQualifiedNames() } const char * -Ndb::externalizeTableName(const char * internalTableName) +Ndb::externalizeTableName(const char * internalTableName, bool fullyQualifiedNames) { if (fullyQualifiedNames) { register const char *ptr = internalTableName; // Skip database name - while (*ptr && *ptr++ != '/'); + while (*ptr && *ptr++ != table_name_separator); // Skip schema name - while (*ptr && *ptr++ != '/'); - + while (*ptr && *ptr++ != table_name_separator); return ptr; } else return internalTableName; } - const char * -Ndb::internalizeTableName(const char * externalTableName) +Ndb::externalizeTableName(const char * internalTableName) { - if (fullyQualifiedNames) { - strncpy(prefixEnd, externalTableName, NDB_MAX_TAB_NAME_SIZE); - return prefixName; - } - else - return externalTableName; + return externalizeTableName(internalTableName, usingFullyQualifiedNames()); } - + const char * -Ndb::externalizeIndexName(const char * internalIndexName) +Ndb::externalizeIndexName(const char * internalIndexName, bool fullyQualifiedNames) { if (fullyQualifiedNames) { register const char *ptr = internalIndexName; // Scan name from the end while (*ptr++); ptr--; // strend - while (ptr >= internalIndexName && *ptr != '/') + while (ptr >= internalIndexName && *ptr != table_name_separator) ptr--; return ptr + 1; @@ -1130,6 +1125,23 @@ Ndb::externalizeIndexName(const char * internalIndexName) else return internalIndexName; } + +const char * +Ndb::externalizeIndexName(const char * internalIndexName) +{ + return externalizeIndexName(internalIndexName, usingFullyQualifiedNames()); +} + +const char * +Ndb::internalizeTableName(const char * externalTableName) +{ + if (fullyQualifiedNames) { + strncpy(prefixEnd, externalTableName, NDB_MAX_TAB_NAME_SIZE); + return prefixName; + } + else + return externalTableName; +} const char * Ndb::internalizeIndexName(const NdbTableImpl * table, @@ -1140,7 +1152,7 @@ Ndb::internalizeIndexName(const NdbTableImpl * table, sprintf(tableId, "%d", table->m_tableId); Uint32 tabIdLen = strlen(tableId); strncpy(prefixEnd, tableId, tabIdLen); - prefixEnd[tabIdLen] = '/'; + prefixEnd[tabIdLen] = table_name_separator; strncpy(prefixEnd + tabIdLen + 1, externalIndexName, NDB_MAX_TAB_NAME_SIZE); return prefixName; @@ -1156,8 +1168,8 @@ Ndb::getDatabaseFromInternalName(const char * internalName) strcpy(databaseName, internalName); register char *ptr = databaseName; - /* Scan name for the first '/' */ - while (*ptr && *ptr != '/') + /* Scan name for the first table_name_separator */ + while (*ptr && *ptr != table_name_separator) ptr++; *ptr = '\0'; BaseString ret = BaseString(databaseName); @@ -1171,12 +1183,12 @@ Ndb::getSchemaFromInternalName(const char * internalName) char * schemaName = new char[strlen(internalName)]; register const char *ptr1 = internalName; - /* Scan name for the second '/' */ - while (*ptr1 && *ptr1 != '/') + /* Scan name for the second table_name_separator */ + while (*ptr1 && *ptr1 != table_name_separator) ptr1++; strcpy(schemaName, ptr1 + 1); register char *ptr = schemaName; - while (*ptr && *ptr != '/') + while (*ptr && *ptr != table_name_separator) ptr++; *ptr = '\0'; BaseString ret = BaseString(schemaName); diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp index a9cd5b1d53a..a44937cd398 100644 --- a/ndb/src/ndbapi/NdbApiSignal.cpp +++ b/ndb/src/ndbapi/NdbApiSignal.cpp @@ -29,7 +29,6 @@ Adjust: 971114 UABMNST First version. ******************************************************************************/ #include "API.hpp" #include "NdbApiSignal.hpp" -#include <AttrType.hpp> /** * The following include includes diff --git a/ndb/src/ndbapi/NdbApiSignal.hpp b/ndb/src/ndbapi/NdbApiSignal.hpp index 76cefe0e882..9d5bc0847be 100644 --- a/ndb/src/ndbapi/NdbApiSignal.hpp +++ b/ndb/src/ndbapi/NdbApiSignal.hpp @@ -31,7 +31,6 @@ #define NdbApiSignal_H #include <kernel_types.h> -#include "AttrType.hpp" #include "TransporterFacade.hpp" #include <TransporterDefinitions.hpp> #include "Ndb.hpp" diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp new file mode 100644 index 00000000000..8e067f770e8 --- /dev/null +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -0,0 +1,1349 @@ +/* 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 */ + +#include "Ndb.hpp" +#include "NdbDictionaryImpl.hpp" +#include "NdbConnection.hpp" +#include "NdbOperation.hpp" +#include "NdbIndexOperation.hpp" +#include "NdbRecAttr.hpp" +#include "NdbBlob.hpp" + +#ifdef NDB_BLOB_DEBUG +#define DBG(x) \ + do { \ + static const char* p = getenv("NDB_BLOB_DEBUG"); \ + if (p == 0 || *p == 0 || *p == '0') break; \ + const char* cname = theColumn == NULL ? "BLOB" : theColumn->m_name.c_str(); \ + ndbout << cname << " " << __LINE__ << " " << x << " " << *this << endl; \ + } while (0) +#define EXE() assert(theNdbCon->executeNoBlobs(NoCommit) == 0) +#else +#define DBG(x) +#endif + +static char* +ndb_blob_debug(const Uint32* data, unsigned size) +{ + static char buf[128 + 1]; // MT irrelevant + buf[0] = 0; + for (unsigned i = 0; i < size && i < 128 / 4; i++) { + sprintf(buf + strlen(buf), "%*s%08x", i != 0, "", data[i]); + } + return buf; +} + +/* + * Reading index table directly (as a table) is faster but there are + * bugs or limitations. Keep the code but make possible to choose. + */ +static const bool g_ndb_blob_ok_to_read_index_table = false; + +// state (inline) + +inline void +NdbBlob::setState(State newState) +{ + DBG("setState " << newState); + theState = newState; +} + +// define blob table + +int +NdbBlob::getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName) +{ + NdbTableImpl* t = anNdb->theDictionary->m_impl.getTable(tableName); + if (t == NULL) + return -1; + NdbColumnImpl* c = t->getColumn(columnName); + if (c == NULL) + return -1; + getBlobTableName(btname, t, c); + return 0; +} + +void +NdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c) +{ + assert(t != 0 && c != 0 && c->getBlobType()); + memset(btname, 0, BlobTableNameSize); + sprintf(btname, "NDB$BLOB_%d_%d_%d", (int)t->m_tableId, (int)t->m_version, (int)c->m_attrId); +} + +void +NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c) +{ + char btname[BlobTableNameSize]; + getBlobTableName(btname, t, c); + bt.setName(btname); + bt.setLogging(t->getLogging()); + bt.setFragmentType(t->getFragmentType()); + { NdbDictionary::Column bc("DIST"); + bc.setType(NdbDictionary::Column::Unsigned); + bc.setPrimaryKey(true); + bc.setDistributionKey(true); + bt.addColumn(bc); + } + { NdbDictionary::Column bc("PART"); + bc.setType(NdbDictionary::Column::Unsigned); + bc.setPrimaryKey(true); + bt.addColumn(bc); + } + { NdbDictionary::Column bc("PK"); + bc.setType(NdbDictionary::Column::Unsigned); + assert(t->m_sizeOfKeysInWords != 0); + bc.setLength(t->m_sizeOfKeysInWords); + bc.setPrimaryKey(true); + bt.addColumn(bc); + } + { NdbDictionary::Column bc("DATA"); + switch (c->m_type) { + case NdbDictionary::Column::Blob: + bc.setType(NdbDictionary::Column::Binary); + break; + case NdbDictionary::Column::Clob: + bc.setType(NdbDictionary::Column::Char); + break; + default: + assert(false); + break; + } + bc.setLength(c->getPartSize()); + bt.addColumn(bc); + } +} + +// initialization + +NdbBlob::NdbBlob() +{ + init(); +} + +void +NdbBlob::init() +{ + theState = Idle; + theBlobTableName[0] = 0; + theNdb = NULL; + theNdbCon = NULL; + theNdbOp = NULL; + theTable = NULL; + theAccessTable = NULL; + theColumn = NULL; + theFillChar = 0; + theInlineSize = 0; + thePartSize = 0; + theStripeSize = 0; + theGetFlag = false; + theGetBuf = NULL; + theSetFlag = false; + theSetBuf = NULL; + theGetSetBytes = 0; + theHead = NULL; + theInlineData = NULL; + theHeadInlineRecAttr = NULL; + theHeadInlineUpdateFlag = false; + theNewPartFlag = false; + theNullFlag = -1; + theLength = 0; + thePos = 0; + theNext = NULL; +} + +void +NdbBlob::release() +{ + setState(Idle); +} + +// buffers + +NdbBlob::Buf::Buf() : + data(NULL), + size(0), + maxsize(0) +{ +} + +NdbBlob::Buf::~Buf() +{ + delete [] data; +} + +void +NdbBlob::Buf::alloc(unsigned n) +{ + size = n; + if (maxsize < n) { + delete [] data; + // align to Uint64 + if (n % 8 != 0) + n += 8 - n % 8; + data = new char [n]; + maxsize = n; + } +#ifdef VM_TRACE + memset(data, 'X', maxsize); +#endif +} + +// classify operations (inline) + +inline bool +NdbBlob::isTableOp() +{ + return theTable == theAccessTable; +} + +inline bool +NdbBlob::isIndexOp() +{ + return theTable != theAccessTable; +} + +inline bool +NdbBlob::isKeyOp() +{ + return + theNdbOp->theOperationType == NdbOperation::InsertRequest || + theNdbOp->theOperationType == NdbOperation::UpdateRequest || + theNdbOp->theOperationType == NdbOperation::ReadRequest || + theNdbOp->theOperationType == NdbOperation::ReadExclusive || + theNdbOp->theOperationType == NdbOperation::DeleteRequest; +} + +inline bool +NdbBlob::isReadOp() +{ + return + theNdbOp->theOperationType == NdbOperation::ReadRequest || + theNdbOp->theOperationType == NdbOperation::ReadExclusive; +} + +inline bool +NdbBlob::isInsertOp() +{ + return + theNdbOp->theOperationType == NdbOperation::InsertRequest; +} + +inline bool +NdbBlob::isUpdateOp() +{ + return + theNdbOp->theOperationType == NdbOperation::UpdateRequest; +} + +inline bool +NdbBlob::isDeleteOp() +{ + return + theNdbOp->theOperationType == NdbOperation::DeleteRequest; +} + +inline bool +NdbBlob::isScanOp() +{ + return + theNdbOp->theOperationType == NdbOperation::OpenScanRequest || + theNdbOp->theOperationType == NdbOperation::OpenRangeScanRequest; +} + +// computations (inline) + +inline Uint32 +NdbBlob::getPartNumber(Uint64 pos) +{ + assert(pos >= theInlineSize); + return (pos - theInlineSize) / thePartSize; +} + +inline Uint32 +NdbBlob::getPartCount() +{ + if (theLength <= theInlineSize) + return 0; + return 1 + getPartNumber(theLength - 1); +} + +inline Uint32 +NdbBlob::getDistKey(Uint32 part) +{ + assert(theStripeSize != 0); + return (part / theStripeSize) % theStripeSize; +} + +// getters and setters + +int +NdbBlob::getTableKeyValue(NdbOperation* anOp) +{ + Uint32* data = (Uint32*)theKeyBuf.data; + unsigned pos = 0; + DBG("getTableKeyValue"); + for (unsigned i = 0; i < theTable->m_columns.size(); i++) { + NdbColumnImpl* c = theTable->m_columns[i]; + assert(c != NULL); + if (c->m_pk) { + unsigned len = c->m_attrSize * c->m_arraySize; + if (anOp->getValue(c, (char*)&data[pos]) == NULL) { + setErrorCode(anOp); + return -1; + } + // odd bytes receive no data and must be zeroed + while (len % 4 != 0) { + char* p = (char*)&data[pos] + len++; + *p = 0; + } + pos += len / 4; + } + } + assert(pos == theKeyBuf.size / 4); + return 0; +} + +int +NdbBlob::setTableKeyValue(NdbOperation* anOp) +{ + const Uint32* data = (const Uint32*)theKeyBuf.data; + unsigned pos = 0; + const unsigned size = theTable->m_columns.size(); + DBG("setTableKeyValue key=" << ndb_blob_debug(data, size)); + for (unsigned i = 0; i < size; i++) { + NdbColumnImpl* c = theTable->m_columns[i]; + assert(c != NULL); + if (c->m_pk) { + unsigned len = c->m_attrSize * c->m_arraySize; + if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { + setErrorCode(anOp); + return -1; + } + pos += (len + 3) / 4; + } + } + assert(pos == theKeyBuf.size / 4); + return 0; +} + +int +NdbBlob::setAccessKeyValue(NdbOperation* anOp) +{ + const Uint32* data = (const Uint32*)theAccessKeyBuf.data; + unsigned pos = 0; + const unsigned size = theAccessTable->m_columns.size(); + DBG("setAccessKeyValue key=" << ndb_blob_debug(data, size)); + for (unsigned i = 0; i < size; i++) { + NdbColumnImpl* c = theAccessTable->m_columns[i]; + assert(c != NULL); + if (c->m_pk) { + unsigned len = c->m_attrSize * c->m_arraySize; + if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { + setErrorCode(anOp); + return -1; + } + pos += (len + 3) / 4; + } + } + assert(pos == theAccessKeyBuf.size / 4); + return 0; +} + +int +NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part) +{ + Uint32* data = (Uint32*)theKeyBuf.data; + unsigned size = theTable->m_sizeOfKeysInWords; + DBG("setPartKeyValue dist=" << getDistKey(part) << " part=" << part << " key=" << ndb_blob_debug(data, size)); + if (anOp->equal((Uint32)0, getDistKey(part)) == -1 || + anOp->equal((Uint32)1, part) == -1 || + anOp->equal((Uint32)2, theKeyBuf.data) == -1) { + setErrorCode(anOp); + return -1; + } + return 0; +} + +int +NdbBlob::getHeadInlineValue(NdbOperation* anOp) +{ + DBG("getHeadInlineValue"); + theHeadInlineRecAttr = anOp->getValue(theColumn, theHeadInlineBuf.data); + if (theHeadInlineRecAttr == NULL) { + setErrorCode(anOp); + return -1; + } + return 0; +} + +void +NdbBlob::getHeadFromRecAttr() +{ + assert(theHeadInlineRecAttr != NULL); + theNullFlag = theHeadInlineRecAttr->isNULL(); + assert(theNullFlag != -1); + theLength = ! theNullFlag ? theHead->length : 0; + DBG("getHeadFromRecAttr out"); +} + +int +NdbBlob::setHeadInlineValue(NdbOperation* anOp) +{ + DBG("setHeadInlineValue"); + theHead->length = theLength; + if (theLength < theInlineSize) + memset(theInlineData + theLength, 0, theInlineSize - theLength); + assert(theNullFlag != -1); + const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data; + if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) { + setErrorCode(anOp); + return -1; + } + theHeadInlineUpdateFlag = false; + return 0; +} + +// getValue/setValue + +int +NdbBlob::getValue(void* data, Uint32 bytes) +{ + DBG("getValue data=" << hex << data << " bytes=" << dec << bytes); + if (theGetFlag || theState != Prepared) { + setErrorCode(ErrState); + return -1; + } + if (! isReadOp() && ! isScanOp()) { + setErrorCode(ErrUsage); + return -1; + } + if (data == NULL && bytes != 0) { + setErrorCode(ErrUsage); + return -1; + } + theGetFlag = true; + theGetBuf = static_cast<char*>(data); + theGetSetBytes = bytes; + return 0; +} + +int +NdbBlob::setValue(const void* data, Uint32 bytes) +{ + DBG("setValue data=" << hex << data << " bytes=" << dec << bytes); + if (theSetFlag || theState != Prepared) { + setErrorCode(ErrState); + return -1; + } + if (! isInsertOp() && ! isUpdateOp()) { + setErrorCode(ErrUsage); + return -1; + } + if (data == NULL && bytes != 0) { + setErrorCode(ErrUsage); + return -1; + } + theSetFlag = true; + theSetBuf = static_cast<const char*>(data); + theGetSetBytes = bytes; + if (isInsertOp()) { + // write inline part now + if (theSetBuf != 0) { + unsigned n = theGetSetBytes; + if (n > theInlineSize) + n = theInlineSize; + if (writeDataPrivate(0, theSetBuf, n) == -1) + return -1; + } else { + theNullFlag = true; + theLength = 0; + } + if (setHeadInlineValue(theNdbOp) == -1) + return -1; + } + return 0; +} + +// misc operations + +int +NdbBlob::getNull(bool& isNull) +{ + if (theState == Prepared && theSetFlag) { + isNull = (theSetBuf == NULL); + return 0; + } + if (theNullFlag == -1) { + setErrorCode(ErrState); + return -1; + } + isNull = theNullFlag; + return 0; +} + +int +NdbBlob::setNull() +{ + DBG("setNull"); + if (theNullFlag == -1) { + if (theState == Prepared) { + return setValue(0, 0); + } + setErrorCode(ErrState); + return -1; + } + if (theNullFlag) + return 0; + if (deleteParts(0, getPartCount()) == -1) + return -1; + theNullFlag = true; + theLength = 0; + theHeadInlineUpdateFlag = true; + return 0; +} + +int +NdbBlob::getLength(Uint64& len) +{ + if (theState == Prepared && theSetFlag) { + len = theGetSetBytes; + return 0; + } + if (theNullFlag == -1) { + setErrorCode(ErrState); + return -1; + } + len = theLength; + return 0; +} + +int +NdbBlob::truncate(Uint64 length) +{ + DBG("truncate kength=" << length); + if (theNullFlag == -1) { + setErrorCode(ErrState); + return -1; + } + if (theLength > length) { + if (length >= theInlineSize) { + Uint32 part1 = getPartNumber(length); + Uint32 part2 = getPartNumber(theLength - 1); + assert(part2 >= part1); + if (deleteParts(part1, part2 - part1) == -1) + return -1; + } else { + if (deleteParts(0, getPartCount()) == -1) + return -1; + } + theLength = length; + theHeadInlineUpdateFlag = true; + } + return 0; +} + +int +NdbBlob::getPos(Uint64& pos) +{ + if (theNullFlag == -1) { + setErrorCode(ErrState); + return -1; + } + pos = thePos; + return 0; +} + +int +NdbBlob::setPos(Uint64 pos) +{ + if (theNullFlag == -1) { + setErrorCode(ErrState); + return -1; + } + if (pos > theLength) { + setErrorCode(ErrSeek); + return -1; + } + thePos = pos; + return 0; +} + +// read/write + +int +NdbBlob::readData(void* data, Uint32& bytes) +{ + if (readData(thePos, data, bytes) == -1) + return -1; + thePos += bytes; + assert(thePos <= theLength); + return 0; +} + +int +NdbBlob::readData(Uint64 pos, void* data, Uint32& bytes) +{ + if (theState != Active) { + setErrorCode(ErrState); + return -1; + } + char* buf = static_cast<char*>(data); + return readDataPrivate(pos, buf, bytes); +} + +int +NdbBlob::readDataPrivate(Uint64 pos, char* buf, Uint32& bytes) +{ + DBG("readData pos=" << pos << " bytes=" << bytes); + if (pos > theLength) { + setErrorCode(ErrSeek); + return -1; + } + if (bytes > theLength - pos) + bytes = theLength - pos; + Uint32 len = bytes; + if (len > 0) { + // inline part + if (pos < theInlineSize) { + Uint32 n = theInlineSize - pos; + if (n > len) + n = len; + memcpy(buf, theInlineData + pos, n); + pos += n; + buf += n; + len -= n; + } + } + if (len > 0) { + assert(pos >= theInlineSize); + Uint32 off = (pos - theInlineSize) % thePartSize; + // partial first block + if (off != 0) { + DBG("partial first block pos=" << pos << " len=" << len); + Uint32 part = (pos - theInlineSize) / thePartSize; + if (readParts(thePartBuf.data, part, 1) == -1) + return -1; + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + Uint32 n = thePartSize - off; + if (n > len) + n = len; + memcpy(buf, thePartBuf.data + off, n); + pos += n; + buf += n; + len -= n; + } + } + if (len > 0) { + assert((pos - theInlineSize) % thePartSize == 0); + // complete blocks in the middle + if (len >= thePartSize) { + Uint32 part = (pos - theInlineSize) / thePartSize; + Uint32 count = len / thePartSize; + if (readParts(buf, part, count) == -1) + return -1; + Uint32 n = thePartSize * count; + pos += n; + buf += n; + len -= n; + } + } + if (len > 0) { + // partial last block + DBG("partial last block pos=" << pos << " len=" << len); + assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize); + Uint32 part = (pos - theInlineSize) / thePartSize; + if (readParts(thePartBuf.data, part, 1) == -1) + return -1; + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + memcpy(buf, thePartBuf.data, len); + Uint32 n = len; + pos += n; + buf += n; + len -= n; + } + assert(len == 0); + return 0; +} + +int +NdbBlob::writeData(const void* data, Uint32 bytes) +{ + if (writeData(thePos, data, bytes) == -1) + return -1; + thePos += bytes; + assert(thePos <= theLength); + return 0; +} + +int +NdbBlob::writeData(Uint64 pos, const void* data, Uint32 bytes) +{ + if (theState != Active) { + setErrorCode(ErrState); + return -1; + } + const char* buf = static_cast<const char*>(data); + return writeDataPrivate(pos, buf, bytes); +} + +int +NdbBlob::writeDataPrivate(Uint64 pos, const char* buf, Uint32 bytes) +{ + DBG("writeData pos=" << pos << " bytes=" << bytes); + if (pos > theLength) { + setErrorCode(ErrSeek); + return -1; + } + Uint32 len = bytes; + // any write makes blob not NULL + if (theNullFlag) { + theNullFlag = false; + theHeadInlineUpdateFlag = true; + } + if (len > 0) { + // inline part + if (pos < theInlineSize) { + Uint32 n = theInlineSize - pos; + if (n > len) + n = len; + memcpy(theInlineData + pos, buf, n); + theHeadInlineUpdateFlag = true; + pos += n; + buf += n; + len -= n; + } + } + if (len > 0) { + assert(pos >= theInlineSize); + Uint32 off = (pos - theInlineSize) % thePartSize; + // partial first block + if (off != 0) { + DBG("partial first block pos=" << pos << " len=" << len); + if (theNewPartFlag) { + // must flush insert to guarantee read + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + theNewPartFlag = false; + } + Uint32 part = (pos - theInlineSize) / thePartSize; + if (readParts(thePartBuf.data, part, 1) == -1) + return -1; + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + Uint32 n = thePartSize - off; + if (n > len) { + memset(thePartBuf.data + off + len, theFillChar, n - len); + n = len; + } + memcpy(thePartBuf.data + off, buf, n); + if (updateParts(thePartBuf.data, part, 1) == -1) + return -1; + pos += n; + buf += n; + len -= n; + } + } + if (len > 0) { + assert((pos - theInlineSize) % thePartSize == 0); + // complete blocks in the middle + if (len >= thePartSize) { + Uint32 part = (pos - theInlineSize) / thePartSize; + Uint32 count = len / thePartSize; + for (unsigned i = 0; i < count; i++) { + if (part + i < getPartCount()) { + if (updateParts(buf, part + i, 1) == -1) + return -1; + } else { + if (insertParts(buf, part + i, 1) == -1) + return -1; + } + Uint32 n = thePartSize; + pos += n; + buf += n; + len -= n; + } + } + } + if (len > 0) { + // partial last block + DBG("partial last block pos=" << pos << " len=" << len); + assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize); + Uint32 part = (pos - theInlineSize) / thePartSize; + if (theLength > pos + len) { + if (theNewPartFlag) { + // must flush insert to guarantee read + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + theNewPartFlag = false; + } + if (readParts(thePartBuf.data, part, 1) == -1) + return -1; + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode(theNdbOp); + return -1; + } + memcpy(thePartBuf.data, buf, len); + if (updateParts(thePartBuf.data, part, 1) == -1) + return -1; + } else { + memcpy(thePartBuf.data, buf, len); + memset(thePartBuf.data + len, theFillChar, thePartSize - len); + if (part < getPartCount()) { + if (updateParts(thePartBuf.data, part, 1) == -1) + return -1; + } else { + if (insertParts(thePartBuf.data, part, 1) == -1) + return -1; + } + } + Uint32 n = len; + pos += n; + buf += n; + len -= n; + } + assert(len == 0); + if (theLength < pos) { + theLength = pos; + theHeadInlineUpdateFlag = true; + } + DBG("writeData out"); + return 0; +} + +int +NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) +{ + DBG("readParts part=" << part << " count=" << count); + Uint32 n = 0; + while (n < count) { + NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTableName); + if (tOp == NULL || + tOp->readTuple() == -1 || + setPartKeyValue(tOp, part + n) == -1 || + tOp->getValue((Uint32)3, buf) == NULL) { + setErrorCode(tOp); + return -1; + } + buf += thePartSize; + n++; + } + return 0; +} + +int +NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count) +{ + DBG("insertParts part=" << part << " count=" << count); + Uint32 n = 0; + while (n < count) { + NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTableName); + if (tOp == NULL || + tOp->insertTuple() == -1 || + setPartKeyValue(tOp, part + n) == -1 || + tOp->setValue((Uint32)3, buf) == -1) { + setErrorCode(tOp); + return -1; + } + buf += thePartSize; + n++; + theNewPartFlag = true; + } + return 0; +} + +int +NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count) +{ + DBG("updateParts part=" << part << " count=" << count); + Uint32 n = 0; + while (n < count) { + NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTableName); + if (tOp == NULL || + tOp->updateTuple() == -1 || + setPartKeyValue(tOp, part + n) == -1 || + tOp->setValue((Uint32)3, buf) == -1) { + setErrorCode(tOp); + return -1; + } + buf += thePartSize; + n++; + theNewPartFlag = true; + } + return 0; +} + +int +NdbBlob::deleteParts(Uint32 part, Uint32 count) +{ + DBG("deleteParts part=" << part << " count=" << count); + Uint32 n = 0; + while (n < count) { + NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTableName); + if (tOp == NULL || + tOp->deleteTuple() == -1 || + setPartKeyValue(tOp, part + n) == -1) { + setErrorCode(tOp); + return -1; + } + n++; + } + return 0; +} + +// blob handle maintenance + +/* + * Prepare blob handle linked to an operation. Checks blob table. + * Allocates buffers. For key operation fetches key data from signal + * data. For read operation adds read of head+inline. + */ +int +NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn) +{ + assert(theState == Idle); + // ndb api stuff + theNdb = anOp->theNdb; + theNdbCon = aCon; // for scan, this is the real transaction (m_transConnection) + theNdbOp = anOp; + theTable = anOp->m_currentTable; + theAccessTable = anOp->m_accessTable; + theColumn = aColumn; + DBG("atPrepare"); + NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined; + switch (theColumn->getType()) { + case NdbDictionary::Column::Blob: + partType = NdbDictionary::Column::Binary; + theFillChar = 0x0; + break; + case NdbDictionary::Column::Clob: + partType = NdbDictionary::Column::Char; + theFillChar = 0x20; + break; + default: + setErrorCode(ErrUsage); + return -1; + } + // sizes + theInlineSize = theColumn->getInlineSize(); + thePartSize = theColumn->getPartSize(); + theStripeSize = theColumn->getStripeSize(); + // blob table sanity check + assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head)); + assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) + theInlineSize); + getBlobTableName(theBlobTableName, theTable, theColumn); + const NdbDictionary::Table* bt; + const NdbDictionary::Column* bc; + if (theInlineSize >= (1 << 16) || + thePartSize == 0 || + thePartSize >= (1 << 16) || + theStripeSize == 0 || + (bt = theNdb->theDictionary->getTable(theBlobTableName)) == NULL || + (bc = bt->getColumn("DATA")) == NULL || + bc->getType() != partType || + bc->getLength() != (int)thePartSize) { + setErrorCode(ErrTable); + return -1; + } + // buffers + theKeyBuf.alloc(theTable->m_sizeOfKeysInWords << 2); + theAccessKeyBuf.alloc(theAccessTable->m_sizeOfKeysInWords << 2); + theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize); + thePartBuf.alloc(thePartSize); + theHead = (Head*)theHeadInlineBuf.data; + theInlineData = theHeadInlineBuf.data + sizeof(Head); + // handle different operation types + bool supportedOp = false; + if (isKeyOp()) { + if (isTableOp()) { + // get table key + Uint32* data = (Uint32*)theKeyBuf.data; + unsigned size = theTable->m_sizeOfKeysInWords; + if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { + setErrorCode(ErrUsage); + return -1; + } + } + if (isIndexOp()) { + // get index key + Uint32* data = (Uint32*)theAccessKeyBuf.data; + unsigned size = theAccessTable->m_sizeOfKeysInWords; + if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { + setErrorCode(ErrUsage); + return -1; + } + } + if (isReadOp()) { + // add read of head+inline in this op + if (getHeadInlineValue(theNdbOp) == -1) + return -1; + } + if (isInsertOp()) { + // becomes NULL unless set before execute + theNullFlag = true; + theLength = 0; + } + supportedOp = true; + } + if (isScanOp()) { + // add read of head+inline in this op + if (getHeadInlineValue(theNdbOp) == -1) + return -1; + supportedOp = true; + } + if (! supportedOp) { + setErrorCode(ErrUsage); + return -1; + } + setState(Prepared); + DBG("atPrepare out"); + return 0; +} + +/* + * Before execute of prepared operation. May add new operations before + * this one. May ask that this operation and all before it (a "batch") + * is executed immediately in no-commit mode. + */ +int +NdbBlob::preExecute(ExecType anExecType, bool& batch) +{ + DBG("preExecute"); + if (theState == Invalid) + return -1; + assert(theState == Prepared); + // handle different operation types + assert(isKeyOp()); + if (isReadOp()) { + if (theGetFlag && theGetSetBytes > theInlineSize) { + // need blob head before proceeding + batch = true; + } + } + if (isInsertOp()) { + if (theSetFlag && theGetSetBytes > theInlineSize) { + // add ops to write rest of a setValue + assert(theSetBuf != 0); + Uint64 pos = theInlineSize; + const char* buf = theSetBuf + theInlineSize; + Uint32 bytes = theGetSetBytes - theInlineSize; + if (writeDataPrivate(pos, buf, bytes) == -1) + return -1; + if (anExecType == Commit && theHeadInlineUpdateFlag) { + // add an operation to update head+inline + NdbOperation* tOp = theNdbCon->getNdbOperation(theTable); + if (tOp == NULL || + tOp->updateTuple() == -1 || + setTableKeyValue(tOp) == -1 || + setHeadInlineValue(tOp) == -1) { + setErrorCode(ErrAbort); + return -1; + } + } + } + } + if (isTableOp()) { + if (isUpdateOp() || isDeleteOp()) { + // add operation before this one to read head+inline + NdbOperation* tOp = theNdbCon->getNdbOperation(theTable, theNdbOp); + if (tOp == NULL || + tOp->readTuple() == -1 || + setTableKeyValue(tOp) == -1 || + getHeadInlineValue(tOp) == -1) { + setErrorCode(tOp); + return -1; + } + // execute immediately + batch = true; + } + } + if (isIndexOp()) { + // add op before this one to read table key + NdbBlob* tFirstBlob = theNdbOp->theBlobList; + if (this == tFirstBlob) { + // first blob does it for all + if (g_ndb_blob_ok_to_read_index_table) { + Uint32 pkAttrId = theAccessTable->getNoOfColumns() - 1; + NdbOperation* tOp = theNdbCon->getNdbOperation(theAccessTable, theNdbOp); + if (tOp == NULL || + tOp->readTuple() == -1 || + setAccessKeyValue(tOp) == -1 || + tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) { + setErrorCode(tOp); + return -1; + } + } else { + NdbOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp); + if (tOp == NULL || + tOp->readTuple() == -1 || + setAccessKeyValue(tOp) == -1 || + getTableKeyValue(tOp) == -1) { + setErrorCode(tOp); + return -1; + } + } + } + if (isUpdateOp() || isDeleteOp()) { + // add op before this one to read head+inline via index + NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp); + if (tOp == NULL || + tOp->readTuple() == -1 || + setAccessKeyValue(tOp) == -1 || + getHeadInlineValue(tOp) == -1) { + setErrorCode(tOp); + return -1; + } + // execute immediately + batch = true; + } + } + DBG("preExecute out batch=" << batch); + return 0; +} + +/* + * After execute, for any operation. If already Active, this routine + * has been done previously. Operations which requested a no-commit + * batch can add new operations after this one. They are added before + * any remaining prepared operations. + */ +int +NdbBlob::postExecute(ExecType anExecType) +{ + DBG("postExecute type=" << anExecType); + if (theState == Invalid) + return -1; + if (theState == Active) + return 0; + assert(theState == Prepared); + assert(isKeyOp()); + if (isIndexOp()) { + NdbBlob* tFirstBlob = theNdbOp->theBlobList; + if (this != tFirstBlob) { + // copy key from first blob + assert(theKeyBuf.size == tFirstBlob->theKeyBuf.size); + memcpy(theKeyBuf.data, tFirstBlob->theKeyBuf.data, tFirstBlob->theKeyBuf.size); + } + } + if (isReadOp()) { + getHeadFromRecAttr(); + if (theGetFlag && theGetSetBytes > 0) { + // copy inline bytes to user buffer + assert(theGetBuf != NULL); + unsigned n = theGetSetBytes; + if (n > theInlineSize) + n = theInlineSize; + memcpy(theGetBuf, theInlineData, n); + } + if (theGetFlag && theGetSetBytes > theInlineSize) { + // add ops to read rest of a getValue + assert(anExecType == NoCommit); + assert(theGetBuf != 0); + Uint64 pos = theInlineSize; + char* buf = theGetBuf + theInlineSize; + Uint32 bytes = theGetSetBytes - theInlineSize; + if (readDataPrivate(pos, buf, bytes) == -1) + return -1; + } + } + if (isUpdateOp()) { + assert(anExecType == NoCommit); + getHeadFromRecAttr(); + if (theSetFlag) { + // setValue overwrites everything + if (theSetBuf != 0) { + if (truncate(0) == -1) + return -1; + if (writeDataPrivate(0, theSetBuf, theGetSetBytes) == -1) + return -1; + } else { + if (setNull() == -1) + return -1; + } + } + } + if (isDeleteOp()) { + assert(anExecType == NoCommit); + getHeadFromRecAttr(); + if (deleteParts(0, getPartCount()) == -1) + return -1; + } + theNewPartFlag = false; + setState(anExecType == NoCommit ? Active : Closed); + DBG("postExecute out"); + return 0; +} + +/* + * Before commit of completed operation. For write add operation to + * update head+inline. + */ +int +NdbBlob::preCommit() +{ + DBG("preCommit"); + if (theState == Invalid) + return -1; + assert(theState == Active); + assert(isKeyOp()); + if (isInsertOp() || isUpdateOp()) { + if (theHeadInlineUpdateFlag) { + // add an operation to update head+inline + NdbOperation* tOp = theNdbCon->getNdbOperation(theTable); + if (tOp == NULL || + tOp->updateTuple() == -1 || + setTableKeyValue(tOp) == -1 || + setHeadInlineValue(tOp) == -1) { + setErrorCode(ErrAbort); + return -1; + } + } + } + DBG("preCommit out"); + return 0; +} + +/* + * After next scan result. Handle like read op above. + */ +int +NdbBlob::atNextResult() +{ + DBG("atNextResult"); + if (theState == Invalid) + return -1; + assert(isScanOp()); + getHeadFromRecAttr(); + // reset position + thePos = 0; + // get primary key + { Uint32* data = (Uint32*)theKeyBuf.data; + unsigned size = theTable->m_sizeOfKeysInWords; + if (theNdbOp->getKeyFromKEYINFO20(data, size) == -1) { + setErrorCode(ErrUsage); + return -1; + } + } + if (! theNullFlag) { + if (theGetFlag && theGetSetBytes > 0) { + // copy inline bytes to user buffer + assert(theGetBuf != NULL); + unsigned n = theGetSetBytes; + if (n > theLength) + n = theLength; + if (n > theInlineSize) + n = theInlineSize; + memcpy(theGetBuf, theInlineData, n); + } + if (theGetFlag && theGetSetBytes > theInlineSize && theLength > theInlineSize) { + // add ops to read rest of a getValue + assert(theGetBuf != 0); + Uint64 pos = theInlineSize; + char* buf = theGetBuf + theInlineSize; + Uint32 bytes = theGetSetBytes - theInlineSize; + if (readDataPrivate(pos, buf, bytes) == -1) + return -1; + // must also execute them + DBG("force execute"); + if (theNdbCon->executeNoBlobs(NoCommit) == -1) { + setErrorCode((NdbOperation*)0); + return -1; + } + } + } + setState(Active); + DBG("atNextResult out"); + return 0; +} + + +// misc + +const NdbDictionary::Column* +NdbBlob::getColumn() +{ + return theColumn; +} + +// errors + +void +NdbBlob::setErrorCode(int anErrorCode, bool invalidFlag) +{ + DBG("setErrorCode code=" << anErrorCode); + theError.code = anErrorCode; + if (invalidFlag) + setState(Invalid); +} + +void +NdbBlob::setErrorCode(NdbOperation* anOp, bool invalidFlag) +{ + int code = 0; + if (anOp != NULL && (code = anOp->theError.code) != 0) + ; + else if ((code = theNdbCon->theError.code) != 0) + ; + else if ((code = theNdb->theError.code) != 0) + ; + else + code = ErrUnknown; + setErrorCode(code, invalidFlag); +} + +void +NdbBlob::setErrorCode(NdbConnection* aCon, bool invalidFlag) +{ + int code = 0; + if (theNdbCon != NULL && (code = theNdbCon->theError.code) != 0) + ; + else if ((code = theNdb->theError.code) != 0) + ; + else + code = ErrUnknown; + setErrorCode(code, invalidFlag); +} + +#ifdef VM_TRACE +NdbOut& +operator<<(NdbOut& out, const NdbBlob& blob) +{ + ndbout << dec << "s=" << blob.theState; + ndbout << dec << " n=" << blob.theNullFlag;; + ndbout << dec << " l=" << blob.theLength; + ndbout << dec << " p=" << blob.thePos; + ndbout << dec << " u=" << blob.theHeadInlineUpdateFlag; + return out; +} +#endif diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index 4ec098c3c60..ad415b8acbf 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -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() /***************************************************************************** @@ -251,6 +255,86 @@ 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 // since last execute or since beginning. If this works ok we will continue @@ -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 { @@ -1706,7 +1818,7 @@ NdbConnection::getTransactionId() return theTransactionId; }//NdbConnection::getTransactionId() -CommitStatusType +NdbConnection::CommitStatusType NdbConnection::commitStatus() { return theCommitStatus; diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp index b068ea6460f..413ad0745db 100644 --- a/ndb/src/ndbapi/NdbDictionary.cpp +++ b/ndb/src/ndbapi/NdbDictionary.cpp @@ -103,6 +103,11 @@ NdbDictionary::Column::getLength() const{ return m_impl.m_length; } +int +NdbDictionary::Column::getSize() const{ + return m_impl.m_attrSize; +} + void NdbDictionary::Column::setNullable(bool val){ m_impl.m_nullable = val; @@ -234,7 +239,7 @@ NdbDictionary::Table::~Table(){ } NdbDictionary::Table& -NdbDictionary::Table::operator=(const NdbDictionary::Table::Table& table) +NdbDictionary::Table::operator=(const NdbDictionary::Table& table) { m_impl.assign(table.m_impl); @@ -268,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(); } @@ -797,3 +805,74 @@ const struct NdbError & NdbDictionary::Dictionary::getNdbError() const { return m_impl.getNdbError(); } + +NdbOut& operator <<(NdbOut& ndbout, const NdbDictionary::Column::Type type) +{ + switch(type){ + case NdbDictionary::Column::Bigunsigned: + ndbout << "Bigunsigned"; + break; + case NdbDictionary::Column::Unsigned: + ndbout << "Unsigned"; + break; + case NdbDictionary::Column::Smallunsigned: + ndbout << "Smallunsigned"; + break; + case NdbDictionary::Column::Tinyunsigned: + ndbout << "Tinyunsigned"; + break; + case NdbDictionary::Column::Bigint: + ndbout << "Bigint"; + break; + case NdbDictionary::Column::Int: + ndbout << "Int"; + break; + case NdbDictionary::Column::Smallint: + ndbout << "Smallint"; + break; + case NdbDictionary::Column::Tinyint: + ndbout << "Tinyint"; + break; + case NdbDictionary::Column::Char: + ndbout << "Char"; + break; + case NdbDictionary::Column::Varchar: + ndbout << "Varchar"; + break; + case NdbDictionary::Column::Float: + ndbout << "Float"; + break; + case NdbDictionary::Column::Double: + ndbout << "Double"; + break; + case NdbDictionary::Column::Mediumint: + ndbout << "Mediumint"; + break; + case NdbDictionary::Column::Mediumunsigned: + ndbout << "Mediumunsigend"; + break; + case NdbDictionary::Column::Binary: + ndbout << "Binary"; + break; + case NdbDictionary::Column::Varbinary: + ndbout << "Varbinary"; + break; + case NdbDictionary::Column::Decimal: + ndbout << "Decimal"; + break; + case NdbDictionary::Column::Timespec: + ndbout << "Timespec"; + break; + case NdbDictionary::Column::Blob: + ndbout << "Blob"; + break; + case NdbDictionary::Column::Undefined: + ndbout << "Undefined"; + break; + default: + ndbout << "Unknown type=" << (Uint32)type; + break; + } + + return ndbout; +} diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 02e3ee23f9c..9589639a332 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -17,7 +17,6 @@ #include "NdbDictionaryImpl.hpp" #include "API.hpp" #include <NdbOut.hpp> -#include <AttrType.hpp> #include "NdbApiSignal.hpp" #include "TransporterFacade.hpp" #include <signaldata/GetTabInfo.hpp> @@ -35,6 +34,7 @@ #include <AttributeList.hpp> #include <NdbEventOperation.hpp> #include "NdbEventOperationImpl.hpp" +#include "NdbBlob.hpp" #define DEBUG_PRINT 0 #define INCOMPATIBLE_VERSION -2 @@ -56,8 +56,8 @@ NdbColumnImpl::NdbColumnImpl(NdbDictionary::Column & f) init(); } -NdbColumnImpl::NdbColumnImpl& -NdbColumnImpl::operator=(const NdbColumnImpl::NdbColumnImpl& col) +NdbColumnImpl& +NdbColumnImpl::operator=(const NdbColumnImpl& col) { m_attrId = col.m_attrId; m_name = col.m_name; @@ -179,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){ @@ -224,6 +231,8 @@ NdbTableImpl::NdbTableImpl() : NdbDictionary::Table(* this), m_facade(this) { m_noOfKeys = 0; + m_sizeOfKeysInWords = 0; + m_noOfBlobs = 0; m_index = 0; init(); } @@ -258,6 +267,8 @@ NdbTableImpl::init(){ m_indexType = NdbDictionary::Index::Undefined; m_noOfKeys = 0; + m_sizeOfKeysInWords = 0; + m_noOfBlobs = 0; } bool @@ -337,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; @@ -622,7 +635,7 @@ NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index, const char * internalName = m_ndb.internalizeIndexName(table, index->getName()); - return getTable(Ndb::externalizeTableName(internalName)); + return getTable(m_ndb.externalizeTableName(internalName)); } bool @@ -863,7 +876,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal, * get tab info */ NdbTableImpl * -NdbDictInterface::getTable(int tableId) +NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames) { NdbApiSignal tSignal(m_reference); GetTabInfoReq * const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend()); @@ -877,11 +890,11 @@ NdbDictInterface::getTable(int tableId) tSignal.theVerId_signalNumber = GSN_GET_TABINFOREQ; tSignal.theLength = GetTabInfoReq::SignalLength; - return getTable(&tSignal, 0, 0); + return getTable(&tSignal, 0, 0, fullyQualifiedNames); } NdbTableImpl * -NdbDictInterface::getTable(const char * name) +NdbDictInterface::getTable(const char * name, bool fullyQualifiedNames) { NdbApiSignal tSignal(m_reference); GetTabInfoReq * const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend()); @@ -905,13 +918,13 @@ NdbDictInterface::getTable(const char * name) ptr[0].p = (Uint32*)name; ptr[0].sz = strLen; - return getTable(&tSignal, ptr, 1); + return getTable(&tSignal, ptr, 1, fullyQualifiedNames); } NdbTableImpl * NdbDictInterface::getTable(class NdbApiSignal * signal, LinearSectionPtr ptr[3], - Uint32 noOfSections) + Uint32 noOfSections, bool fullyQualifiedNames) { //GetTabInfoReq * const req = CAST_PTR(GetTabInfoReq, signal->getDataPtrSend()); int r = dictSignal(signal,ptr,noOfSections, @@ -925,7 +938,7 @@ NdbDictInterface::getTable(class NdbApiSignal * signal, NdbTableImpl * rt = 0; m_error.code = parseTableInfo(&rt, (Uint32*)m_buffer.get_data(), - m_buffer.length() / 4); + m_buffer.length() / 4, fullyQualifiedNames); rt->buildColumnHash(); return rt; } @@ -1077,12 +1090,15 @@ 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 } }; int NdbDictInterface::parseTableInfo(NdbTableImpl ** ret, - const Uint32 * data, Uint32 len) + const Uint32 * data, Uint32 len, + bool fullyQualifiedNames) { SimplePropertiesLinearReader it(data, len); DictTabInfo::Table tableDesc; tableDesc.init(); @@ -1096,7 +1112,7 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret, return 703; } const char * internalName = tableDesc.TableName; - const char * externalName = Ndb::externalizeTableName(internalName); + const char * externalName = Ndb::externalizeTableName(internalName, fullyQualifiedNames); NdbTableImpl * impl = new NdbTableImpl(); impl->m_tableId = tableDesc.TableId; @@ -1125,12 +1141,13 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret, if(impl->m_indexType == NdbDictionary::Index::Undefined){ } else { const char * externalPrimary = - Ndb::externalizeTableName(tableDesc.PrimaryTable); + Ndb::externalizeTableName(tableDesc.PrimaryTable, fullyQualifiedNames); impl->m_primaryTable.assign(externalPrimary); } 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) @@ -1257,7 +1315,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, NdbTableImpl & impl, bool alter) { - if((unsigned)impl.getNoOfPrimaryKeys() > MAXNROFTUPLEKEY){ + if((unsigned)impl.getNoOfPrimaryKeys() > NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY){ m_error.code = 4317; return -1; } @@ -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(); @@ -1555,6 +1619,23 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl) } 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) { NdbApiSignal tSignal(m_reference); @@ -1867,7 +1948,7 @@ int NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) { const char * indexName = impl.getName(); - if (tableName || Ndb::usingFullyQualifiedNames()) { + if (tableName || m_ndb.usingFullyQualifiedNames()) { NdbTableImpl * timpl = impl.m_table; if (timpl == 0) { @@ -2572,14 +2653,13 @@ NdbDictionaryImpl::listObjects(List& list, NdbDictionary::Object::Type type) req.requestData = 0; req.setTableType(getKernelConstant(type, objectTypeMapping, 0)); req.setListNames(true); - return m_receiver.listObjects(list, req.requestData); + return m_receiver.listObjects(list, req.requestData, m_ndb.usingFullyQualifiedNames()); } int NdbDictionaryImpl::listIndexes(List& list, const char * tableName) { - ListTablesReq - req; + ListTablesReq req; NdbTableImpl* impl = getTable(tableName); if (impl == 0) return -1; @@ -2587,12 +2667,12 @@ NdbDictionaryImpl::listIndexes(List& list, const char * tableName) req.setTableId(impl->m_tableId); req.setListNames(true); req.setListIndexes(true); - return m_receiver.listObjects(list, req.requestData); + return m_receiver.listObjects(list, req.requestData, m_ndb.usingFullyQualifiedNames()); } int NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list, - Uint32 requestData) + Uint32 requestData, bool fullyQualifiedNames) { NdbApiSignal tSignal(m_reference); ListTablesReq* const req = CAST_PTR(ListTablesReq, tSignal.getDataPtrSend()); @@ -2657,7 +2737,7 @@ NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list, memcpy(indexName, &data[pos], n << 2); databaseName = Ndb::getDatabaseFromInternalName(indexName); schemaName = Ndb::getSchemaFromInternalName(indexName); - objectName = BaseString(Ndb::externalizeIndexName(indexName)); + objectName = BaseString(Ndb::externalizeIndexName(indexName, fullyQualifiedNames)); delete [] indexName; } else if ((element.type == NdbDictionary::Object::SystemTable) || (element.type == NdbDictionary::Object::UserTable)) { @@ -2665,7 +2745,7 @@ NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list, memcpy(tableName, &data[pos], n << 2); databaseName = Ndb::getDatabaseFromInternalName(tableName); schemaName = Ndb::getSchemaFromInternalName(tableName); - objectName = BaseString(Ndb::externalizeTableName(tableName)); + objectName = BaseString(Ndb::externalizeTableName(tableName, fullyQualifiedNames)); delete [] tableName; } else { diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 3263a636a79..bf59838c198 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -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 @@ -283,17 +286,18 @@ public: int stopSubscribeEvent(class Ndb & ndb, NdbEventImpl &); int stopSubscribeEvent(NdbApiSignal* signal, LinearSectionPtr ptr[3]); - int listObjects(NdbDictionary::Dictionary::List& list, Uint32 requestData); + int listObjects(NdbDictionary::Dictionary::List& list, Uint32 requestData, bool fullyQualifiedNames); int listObjects(NdbApiSignal* signal); - NdbTableImpl * getTable(int tableId); - NdbTableImpl * getTable(const char * name); + NdbTableImpl * getTable(int tableId, bool fullyQualifiedNames); + NdbTableImpl * getTable(const char * name, bool fullyQualifiedNames); NdbTableImpl * getTable(class NdbApiSignal * signal, LinearSectionPtr ptr[3], - Uint32 noOfSections); + Uint32 noOfSections, bool fullyQualifiedNames); static int parseTableInfo(NdbTableImpl ** dst, - const Uint32 * data, Uint32 len); + const Uint32 * data, Uint32 len, + bool fullyQualifiedNames); NdbError & m_error; private: @@ -352,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 +435,13 @@ NdbColumnImpl::getInterpretableType() const { } inline +bool +NdbColumnImpl::getBlobType() const { + return (m_type == NdbDictionary::Column::Blob || + m_type == NdbDictionary::Column::Clob); +} + +inline NdbTableImpl & NdbTableImpl::getImpl(NdbDictionary::Table & t){ return t.m_impl; @@ -601,7 +611,7 @@ NdbDictionaryImpl::getTableImpl(const char * internalTableName) m_globalHash->unlock(); if (ret == 0){ - ret = m_receiver.getTable(internalTableName); + ret = m_receiver.getTable(internalTableName, m_ndb.usingFullyQualifiedNames()); m_globalHash->lock(); m_globalHash->put(internalTableName, ret); @@ -624,7 +634,7 @@ NdbIndexImpl * NdbDictionaryImpl::getIndex(const char * indexName, const char * tableName) { - if (tableName || Ndb::usingFullyQualifiedNames()) { + if (tableName || m_ndb.usingFullyQualifiedNames()) { const char * internalIndexName = 0; if (tableName) { NdbTableImpl * t = getTable(tableName); diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp index acc726e28c5..b73a58d97c4 100644 --- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -21,7 +21,6 @@ #include "NdbDictionaryImpl.hpp" #include "API.hpp" #include <NdbOut.hpp> -#include <AttrType.hpp> #include "NdbApiSignal.hpp" #include "TransporterFacade.hpp" #include <signaldata/CreateEvnt.hpp> @@ -489,52 +488,7 @@ NdbEventOperationImpl::getEventType() } } -void -NdbEventOperationImpl::printRecAttr(NdbRecAttr *p) -{ - int size = p->attrSize(); - int aSize = p->arraySize(); - - switch(p->attrType()){ - case UnSigned: - switch(size) { - case 8: ndbout << p->u_64_value(); break; - case 4: ndbout << p->u_32_value(); break; - case 2: ndbout << p->u_short_value(); break; - case 1: ndbout << (unsigned) p->u_char_value(); break; - default: ndbout << "Unknown size" << endl; - } - break; - - case Signed: - switch(size) { - case 8: ndbout << p->int64_value(); break; - case 4: ndbout << p->int32_value(); break; - case 2: ndbout << p->short_value(); break; - case 1: ndbout << (int) p->char_value(); break; - default: ndbout << "Unknown size" << endl; - } - break; - - case String: - { - char* buf = new char[aSize+1]; - memcpy(buf, p->aRef(), aSize); - buf[aSize] = 0; - ndbout << buf; - delete [] buf; - } - break; - - case Float: - ndbout << p->float_value(); - break; - - default: - ndbout << "Unknown"; - break; - } -} + void NdbEventOperationImpl::print() @@ -545,8 +499,7 @@ NdbEventOperationImpl::print() NdbRecAttr *p = theFirstRecAttrs[i]; ndbout << " %u " << i; while (p) { - ndbout << " : " << p->attrId() << " = "; - printRecAttr(p); + ndbout << " : " << p->attrId() << " = " << *p; p = p->next(); } ndbout << "\n"; diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/ndb/src/ndbapi/NdbEventOperationImpl.hpp index b7dee084a9f..f67c998e639 100644 --- a/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -60,7 +60,6 @@ public: void print(); void printAll(); - void printRecAttr(NdbRecAttr *); Ndb *m_ndb; NdbEventImpl *m_eventImpl; diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp index ee5491d72a8..631c09e2e6d 100644 --- a/ndb/src/ndbapi/NdbIndexOperation.cpp +++ b/ndb/src/ndbapi/NdbIndexOperation.cpp @@ -87,7 +87,7 @@ NdbIndexOperation::indxInit(NdbIndexImpl * anIndex, m_accessTable = anIndex->m_table; m_theIndexLen = 0; m_theNoOfIndexDefined = 0; - for (Uint32 i=0; i<MAXNROFTUPLEKEY; i++) + for (Uint32 i=0; i<NDB_MAX_ATTRIBUTES_IN_INDEX; i++) for (int j=0; j<3; j++) m_theIndexDefined[i][j] = false; @@ -221,7 +221,7 @@ int NdbIndexOperation::equal_impl(const NdbColumnImpl* tAttrInfo, goto equal_error2; }//if }//if - } while (i < MAXNROFTUPLEKEY); + } while (i < NDB_MAX_ATTRIBUTES_IN_INDEX); goto equal_error2; } else { goto equal_error1; @@ -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; @@ -695,7 +706,7 @@ NdbIndexOperation::receiveTCINDXREF( NdbApiSignal* aSignal) theStatus = Finished; - theNdbCon->theReturnStatus = ReturnFailure; + theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; //--------------------------------------------------------------------------// // If the transaction this operation belongs to consists only of simple reads // we set the error code on the transaction object. diff --git a/ndb/src/ndbapi/NdbOperation.cpp b/ndb/src/ndbapi/NdbOperation.cpp index ccbfa767542..e6031a58c5f 100644 --- a/ndb/src/ndbapi/NdbOperation.cpp +++ b/ndb/src/ndbapi/NdbOperation.cpp @@ -31,7 +31,8 @@ #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; @@ -163,7 +165,7 @@ NdbOperation::init(NdbTableImpl* tab, NdbConnection* myConnection){ m_currentTable = m_accessTable = tab; theNdbCon = myConnection; - for (Uint32 i=0; i<MAXNROFTUPLEKEY; i++) + for (Uint32 i=0; i<NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; i++) for (int j=0; j<3; j++) theTupleKeyDefined[i][j] = false; @@ -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(); +} diff --git a/ndb/src/ndbapi/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp index 18f8b79d12e..69a6602fe65 100644 --- a/ndb/src/ndbapi/NdbOperationDefine.cpp +++ b/ndb/src/ndbapi/NdbOperationDefine.cpp @@ -31,10 +31,10 @@ #include "NdbConnection.hpp" #include "Ndb.hpp" #include "NdbRecAttr.hpp" -#include "AttrType.hpp" #include "NdbUtil.hpp" #include "NdbOut.hpp" #include "NdbImpl.hpp" +#include "NdbBlob.hpp" #include <Interpreter.hpp> @@ -529,9 +529,9 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, tAttrId = tAttrInfo->m_attrId; const char *aValue = aValuePassed; Uint32 ahValue; - AttributeHeader& ah = AttributeHeader::init(&ahValue, tAttrId, 0); if (aValue == NULL) { if (tAttrInfo->m_nullable) { + AttributeHeader& ah = AttributeHeader::init(&ahValue, tAttrId, 0); ah.setNULL(); insertATTRINFO(ahValue); // Insert Attribute Id with the value @@ -565,7 +565,8 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, }//if const Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Including bits in last word const Uint32 sizeInWords = sizeInBytes / 4; // Excluding bits in last word - ah.setDataSize(totalSizeInWords); + AttributeHeader& ah = AttributeHeader::init(&ahValue, tAttrId, + totalSizeInWords); insertATTRINFO( ahValue ); /*********************************************************************** @@ -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. */ diff --git a/ndb/src/ndbapi/NdbOperationExec.cpp b/ndb/src/ndbapi/NdbOperationExec.cpp index b2a6f99880c..d00c527550d 100644 --- a/ndb/src/ndbapi/NdbOperationExec.cpp +++ b/ndb/src/ndbapi/NdbOperationExec.cpp @@ -757,7 +757,7 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal) theStatus = Finished; - theNdbCon->theReturnStatus = ReturnFailure; + theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; //-------------------------------------------------------------------------// // If the transaction this operation belongs to consists only of simple reads // we set the error code on the transaction object. diff --git a/ndb/src/ndbapi/NdbOperationInt.cpp b/ndb/src/ndbapi/NdbOperationInt.cpp index be23a1c274c..e61fc5b05d7 100644 --- a/ndb/src/ndbapi/NdbOperationInt.cpp +++ b/ndb/src/ndbapi/NdbOperationInt.cpp @@ -31,7 +31,6 @@ Adjust: 991029 UABRONM First version. #include "NdbConnection.hpp" #include "Ndb.hpp" #include "NdbRecAttr.hpp" -#include "AttrType.hpp" #include "NdbUtil.hpp" #include "Interpreter.hpp" @@ -69,7 +68,7 @@ NdbOperation::incCheck(const NdbColumnImpl* tNdbColumnImpl) } return tNdbColumnImpl->m_attrId; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; @@ -121,7 +120,7 @@ NdbOperation::write_attrCheck(const NdbColumnImpl* tNdbColumnImpl) } return tNdbColumnImpl->m_attrId; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; @@ -169,7 +168,7 @@ NdbOperation::read_attrCheck(const NdbColumnImpl* tNdbColumnImpl) } return tNdbColumnImpl->m_attrId; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; @@ -209,7 +208,7 @@ NdbOperation::initial_interpreterCheck() } return 0; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; @@ -235,7 +234,7 @@ NdbOperation::labelCheck() } return 0; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; @@ -255,7 +254,7 @@ NdbOperation::intermediate_interpreterCheck() } return 0; } else { - if (theNdbCon->theCommitStatus == Started) + if (theNdbCon->theCommitStatus == NdbConnection::Started) setErrorCodeAbort(4200); } return -1; diff --git a/ndb/src/ndbapi/NdbOperationScan.cpp b/ndb/src/ndbapi/NdbOperationScan.cpp index df4f2421ec0..299e6f2adea 100644 --- a/ndb/src/ndbapi/NdbOperationScan.cpp +++ b/ndb/src/ndbapi/NdbOperationScan.cpp @@ -31,7 +31,7 @@ NdbOperation::openScanRead(Uint32 aParallelism) { aParallelism = checkParallelism(aParallelism); - if ((theNdbCon->theCommitStatus != Started) && + if ((theNdbCon->theCommitStatus != NdbConnection::Started) && (theStatus != Init) && (aParallelism == 0)) { setErrorCode(4200); @@ -48,7 +48,7 @@ NdbOperation::openScanExclusive(Uint32 aParallelism) { aParallelism = checkParallelism(aParallelism); - if ((theNdbCon->theCommitStatus != Started) && + if ((theNdbCon->theCommitStatus != NdbConnection::Started) && (theStatus != Init) && (aParallelism == 0)) { setErrorCode(4200); @@ -65,7 +65,7 @@ NdbOperation::openScanReadHoldLock(Uint32 aParallelism) { aParallelism = checkParallelism(aParallelism); - if ((theNdbCon->theCommitStatus != Started) && + if ((theNdbCon->theCommitStatus != NdbConnection::Started) && (theStatus != Init) && (aParallelism == 0)) { setErrorCode(4200); @@ -82,7 +82,7 @@ NdbOperation::openScanReadCommitted(Uint32 aParallelism) { aParallelism = checkParallelism(aParallelism); - if ((theNdbCon->theCommitStatus != Started) && + if ((theNdbCon->theCommitStatus != NdbConnection::Started) && (theStatus != Init) && (aParallelism == 0)) { setErrorCode(4200); @@ -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; +} diff --git a/ndb/src/ndbapi/NdbOperationSearch.cpp b/ndb/src/ndbapi/NdbOperationSearch.cpp index e1d5e823077..19cb133dbf7 100644 --- a/ndb/src/ndbapi/NdbOperationSearch.cpp +++ b/ndb/src/ndbapi/NdbOperationSearch.cpp @@ -35,7 +35,6 @@ Adjust: 971022 UABMNST First version. #include <Ndb.hpp> #include "NdbImpl.hpp" #include <NdbOut.hpp> -#include "AttrType.hpp" #include <AttributeHeader.hpp> #include <signaldata/TcKeyReq.hpp> @@ -102,7 +101,7 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo, goto equal_error2; }//if }//if - } while (i < MAXNROFTUPLEKEY); + } while (i < NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY); goto equal_error2; } else { goto equal_error1; @@ -252,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; @@ -498,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; +} diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp index 0f7baeac4f5..0ed2ff4e796 100644 --- a/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/ndb/src/ndbapi/NdbRecAttr.cpp @@ -27,17 +27,14 @@ Documentation: Adjust: 971206 UABRONM First version ************************************************************************************************/ #include <ndb_global.h> -#include "NdbRecAttr.hpp" +#include <NdbOut.hpp> +#include <NdbRecAttr.hpp> #include "NdbDictionaryImpl.hpp" +#include <NdbTCP.h> -NdbRecAttr::NdbRecAttr() : - theStorageX(NULL), - theValue(NULL), - theRef(NULL), - theNext(NULL), - theAttrId(0xFFFF), - theNULLind(-1) -{ +NdbRecAttr::NdbRecAttr() +{ + init(); } NdbRecAttr::~NdbRecAttr() @@ -46,6 +43,11 @@ NdbRecAttr::~NdbRecAttr() } int +NdbRecAttr::setup(const class NdbDictionary::Column* col, char* aValue) +{ + return setup(&(col->m_impl), aValue); +} +int NdbRecAttr::setup(const NdbColumnImpl* anAttrInfo, char* aValue) { Uint32 tAttrSize = anAttrInfo->m_attrSize; @@ -53,6 +55,7 @@ NdbRecAttr::setup(const NdbColumnImpl* anAttrInfo, char* aValue) Uint32 tAttrByteSize = tAttrSize * tArraySize; m_column = anAttrInfo; + theAttrId = anAttrInfo->m_attrId; theAttrSize = tAttrSize; theArraySize = tArraySize; @@ -124,3 +127,79 @@ NdbRecAttr::clone() const { memcpy(ret->theRef, theRef, n); return ret; } + +NdbOut& operator<<(NdbOut& ndbout, const NdbRecAttr &r) +{ + if (r.isNULL()) + { + ndbout << "[NULL]"; + return ndbout; + } + + if (r.arraySize() > 1) + ndbout << "["; + + for (Uint32 j = 0; j < r.arraySize(); j++) + { + if (j > 0) + ndbout << " "; + + switch(r.getType()) + { + case NdbDictionary::Column::Bigunsigned: + ndbout << r.u_64_value(); + break; + case NdbDictionary::Column::Unsigned: + ndbout << r.u_32_value(); + break; + case NdbDictionary::Column::Smallunsigned: + ndbout << r.u_short_value(); + break; + case NdbDictionary::Column::Tinyunsigned: + ndbout << (unsigned) r.u_char_value(); + break; + case NdbDictionary::Column::Bigint: + ndbout << r.int64_value(); + break; + case NdbDictionary::Column::Int: + ndbout << r.int32_value(); + break; + case NdbDictionary::Column::Smallint: + ndbout << r.short_value(); + break; + case NdbDictionary::Column::Tinyint: + ndbout << (int) r.char_value(); + break; + case NdbDictionary::Column::Char: + ndbout.print("%.*s", r.arraySize(), r.aRef()); + j = r.arraySize(); + break; + case NdbDictionary::Column::Varchar: + { + short len = ntohs(r.u_short_value()); + ndbout.print("%.*s", len, r.aRef()+2); + } + j = r.arraySize(); + break; + case NdbDictionary::Column::Float: + ndbout << r.float_value(); + break; + case NdbDictionary::Column::Double: + ndbout << r.double_value(); + break; + default: /* no print functions for the rest, just print type */ + ndbout << r.getType(); + j = r.arraySize(); + if (j > 1) + ndbout << " %u times" << j; + break; + } + } + + if (r.arraySize() > 1) + { + ndbout << "]"; + } + + return ndbout; +} diff --git a/ndb/src/ndbapi/NdbResultSet.cpp b/ndb/src/ndbapi/NdbResultSet.cpp index 8397d5eef91..65ed43f60d8 100644 --- a/ndb/src/ndbapi/NdbResultSet.cpp +++ b/ndb/src/ndbapi/NdbResultSet.cpp @@ -61,7 +61,8 @@ NdbResultSet::updateTuple(){ } NdbScanOperation * op = (NdbScanOperation*)(m_operation); - return op->takeOverScanOp(UpdateRequest, op->m_transConnection); + return op->takeOverScanOp(NdbOperation::UpdateRequest, + op->m_transConnection); } NdbOperation* @@ -71,7 +72,8 @@ NdbResultSet::updateTuple(NdbConnection* takeOverTrans){ return 0; } - return m_operation->takeOverScanOp(UpdateRequest, takeOverTrans); + return m_operation->takeOverScanOp(NdbOperation::UpdateRequest, + takeOverTrans); } int @@ -82,7 +84,8 @@ NdbResultSet::deleteTuple(){ } NdbScanOperation * op = (NdbScanOperation*)(m_operation); - void * res = op->takeOverScanOp(DeleteRequest, op->m_transConnection); + void * res = op->takeOverScanOp(NdbOperation::DeleteRequest, + op->m_transConnection); if(res == 0) return -1; return 0; @@ -95,7 +98,8 @@ NdbResultSet::deleteTuple(NdbConnection * takeOverTrans){ return 0; } - void * res = m_operation->takeOverScanOp(DeleteRequest, takeOverTrans); + void * res = m_operation->takeOverScanOp(NdbOperation::DeleteRequest, + takeOverTrans); if(res == 0) return -1; return 0; diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 4db0f30f56c..cc090ac0364 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -34,6 +34,7 @@ #include "NdbApiSignal.hpp" #include <NdbOut.hpp> #include "NdbDictionaryImpl.hpp" +#include "NdbBlob.hpp" NdbScanOperation::NdbScanOperation(Ndb* aNdb) : NdbCursorOperation(aNdb), @@ -86,8 +87,10 @@ NdbScanOperation::init(NdbTableImpl* tab, NdbConnection* myConnection) m_transConnection = myConnection; //NdbConnection* aScanConnection = theNdb->startTransaction(myConnection); NdbConnection* aScanConnection = theNdb->hupp(myConnection); - if (!aScanConnection) + if (!aScanConnection){ + setErrorCodeAbort(theNdb->getNdbError().code); return -1; + } aScanConnection->theFirstOpInList = this; aScanConnection->theLastOpInList = this; NdbCursorOperation::cursInit(); @@ -106,11 +109,11 @@ NdbResultSet* NdbScanOperation::readTuples(Uint32 parallell, break; case NdbCursorOperation::LM_Exclusive: parallell = (parallell == 0 ? 1 : parallell); - res = openScan(parallell, true, /*irrelevant*/true, /*irrelevant*/false); + res = openScan(parallell, true, true, false); break; case NdbCursorOperation::LM_Dirty: parallell = (parallell == 0 ? 240 : parallell); - res = openScan(parallell, true, /*irrelevant*/true, /*irrelevant*/false); + res = openScan(parallell, false, false, true); break; default: res = -1; @@ -292,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) @@ -342,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; } diff --git a/ndb/src/ndbapi/NdbSchemaCon.cpp b/ndb/src/ndbapi/NdbSchemaCon.cpp deleted file mode 100644 index fbf30c70d12..00000000000 --- a/ndb/src/ndbapi/NdbSchemaCon.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* 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 */ - -/********************************************************************* -Name: NdbSchemaCon.C -Include: -Link: -Author: UABMNST Mona Natterkvist UAB/B/SD - EMIKRON Mikael Ronstrom -Date: 020826 -Version: 2.0 -Description: Interface between application and NDB -Documentation: -Adjust: 980126 UABMNST First version. - 020826 EMIKRON New version adapted to new DICT version -************************************************************************************************/ -#include "NdbSchemaCon.hpp" -#include "NdbSchemaOp.hpp" -#include "NdbApiSignal.hpp" -#include "TransporterFacade.hpp" -#include <RefConvert.hpp> -#include <signaldata/CreateIndx.hpp> -#include <signaldata/DropIndx.hpp> -#include <signaldata/CreateTable.hpp> -#include <NdbOut.hpp> - -/********************************************************************* -NdbSchemaCon(Ndb* aNdb); - -Parameters: aNdb: Pointers to the Ndb object -Remark: Creates a schemacon object. -************************************************************************************************/ -NdbSchemaCon::NdbSchemaCon( Ndb* aNdb ) : - theNdb(aNdb), - theFirstSchemaOpInList(NULL), - theMagicNumber(0x75318642) -{ - theError.code = 0; -}//NdbSchemaCon::NdbSchemaCon() - -/********************************************************************* -~NdbSchemaCon(); - -Remark: Deletes the connection object. -************************************************************************************************/ -NdbSchemaCon::~NdbSchemaCon() -{ -}//NdbSchemaCon::~NdbSchemaCon() - -/********************************************************************* -NdbSchemaOp* getNdbSchemaOp(); - -Return Value Return a pointer to a NdbSchemaOp object if getNdbSchemaOp was sussesful. - Return NULL: In all other case. -Parameters: tableId : Id of the database table beeing deleted. -************************************************************************************************/ -NdbSchemaOp* -NdbSchemaCon::getNdbSchemaOp() -{ - NdbSchemaOp* tSchemaOp; - if (theFirstSchemaOpInList != NULL) { - theError.code = 4401; // Only support one add table per transaction - return NULL; - }//if - tSchemaOp = new NdbSchemaOp(theNdb); - if ( tSchemaOp == NULL ) { - theError.code = 4000; // Could not allocate schema operation - return NULL; - }//if - theFirstSchemaOpInList = tSchemaOp; - int retValue = tSchemaOp->init(this); - if (retValue == -1) { - release(); - theError.code = 4000; // Could not allocate buffer in schema operation - return NULL; - }//if - return tSchemaOp; -}//NdbSchemaCon::getNdbSchemaOp() - -/********************************************************************* -int execute(); - -Return Value: Return 0 : execute was successful. - Return -1: In all other case. -Parameters : aTypeOfExec: Type of execute. -Remark: Initialise connection object for new transaction. -************************************************************************************************/ -int -NdbSchemaCon::execute() -{ - if(theError.code != 0) { - return -1; - }//if - - NdbSchemaOp* tSchemaOp; - - tSchemaOp = theFirstSchemaOpInList; - if (tSchemaOp == NULL) { - theError.code = 4402; - return -1; - }//if - - if ((tSchemaOp->sendRec() == -1) || (theError.code != 0)) { - // Error Code already set in other place - return -1; - }//if - - return 0; -}//NdbSchemaCon::execute() - -/********************************************************************* -void release(); - -Remark: Release all schemaop. -************************************************************************************************/ -void -NdbSchemaCon::release() -{ - NdbSchemaOp* tSchemaOp; - tSchemaOp = theFirstSchemaOpInList; - if (tSchemaOp != NULL) { - tSchemaOp->release(); - delete tSchemaOp; - }//if - theFirstSchemaOpInList = NULL; - return; -}//NdbSchemaCon::release() - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ndb/src/ndbapi/NdbSchemaOp.cpp b/ndb/src/ndbapi/NdbSchemaOp.cpp deleted file mode 100644 index 9e495229661..00000000000 --- a/ndb/src/ndbapi/NdbSchemaOp.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* 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 */ - - -/***************************************************************************** -Name: NdbSchemaOp.C -Include: -Link: -Author: UABMNST Mona Natterkvist UAB/B/SD - EMIKRON Mikael Ronstrom -Date: 020826 -Version: 2.0 -Description: Interface between application and NDB -Documentation: Handles createTable and createAttribute calls - -Adjust: 980125 UABMNST First version. - 020826 EMIKRON New version for new DICT -*****************************************************************************/ -#include <assert.h> -#include "NdbSchemaOp.hpp" -#include "NdbSchemaCon.hpp" -#include "API.hpp" - -/***************************************************************************** -NdbSchemaOp(Ndb* aNdb, Table* aTable); - -Return Value: None -Parameters: aNdb: Pointers to the Ndb object. - aTable: Pointers to the Table object -Remark: Creat an object of NdbSchemaOp. -*****************************************************************************/ -NdbSchemaOp::NdbSchemaOp(Ndb* aNdb) : - theNdb(aNdb), - theSchemaCon(NULL), - m_currentTable(NULL) -{ -}//NdbSchemaOp::NdbSchemaOp() - -/***************************************************************************** -~NdbSchemaOp(); - -Remark: Delete tables for connection pointers (id). -*****************************************************************************/ -NdbSchemaOp::~NdbSchemaOp( ) -{ -}//~NdbSchemaOp::NdbSchemaOp() - -/***************************************************************************** -int createTable( const char* tableName ) -*****************************************************************************/ -int -NdbSchemaOp::createTable(const char* aTableName, - Uint32 aTableSize, - KeyType aTupleKey, - int aNrOfPages, - FragmentType aFragmentType, - int aKValue, - int aMinLoadFactor, - int aMaxLoadFactor, - int aMemoryType, - bool aStoredTable) -{ - if(m_currentTable != 0){ - return -1; - } - - m_currentTable = new NdbDictionary::Table(aTableName); - m_currentTable->setKValue(aKValue); - m_currentTable->setMinLoadFactor(aMinLoadFactor); - m_currentTable->setMaxLoadFactor(aMaxLoadFactor); - m_currentTable->setLogging(aStoredTable); - m_currentTable->setFragmentType(NdbDictionary::Object::FragAllMedium); - return 0; -}//NdbSchemaOp::createTable() - -/****************************************************************************** -int createAttribute( const char* anAttrName, - KeyType aTupleyKey, - int anAttrSize, - int anArraySize, - AttrType anAttrType, - SafeType aSafeType, - StorageMode aStorageMode, - int aNullAttr, - int aStorageAttr ); - -******************************************************************************/ -int -NdbSchemaOp::createAttribute( const char* anAttrName, - KeyType aTupleKey, - int anAttrSize, - int anArraySize, - AttrType anAttrType, - StorageMode aStorageMode, - bool nullable, - StorageAttributeType aStorageAttr, - int aDistributionKeyFlag, - int aDistributionGroupFlag, - int aDistributionGroupNoOfBits, - bool aAutoIncrement, - const char* aDefaultValue) -{ - if (m_currentTable == 0){ - return -1; - }//if - - NdbDictionary::Column col(anAttrName); - switch(anAttrType){ - case Signed: - if(anAttrSize == 64) - col.setType(NdbDictionary::Column::Bigint); - else - col.setType(NdbDictionary::Column::Int); - break; - case UnSigned: - if(anAttrSize == 64) - col.setType(NdbDictionary::Column::Bigunsigned); - else - col.setType(NdbDictionary::Column::Unsigned); - break; - case Float: - if(anAttrSize == 64) - col.setType(NdbDictionary::Column::Double); - else - col.setType(NdbDictionary::Column::Float); - break; - case String: - col.setType(NdbDictionary::Column::Char); - break; - case NoAttrTypeDef: - abort(); - } - col.setLength(anArraySize); - col.setNullable(nullable); - if(aTupleKey != NoKey) - col.setPrimaryKey(true); - else - col.setPrimaryKey(false); - - col.setDistributionKey(aDistributionKeyFlag); - col.setDistributionGroup(aDistributionGroupFlag,aDistributionGroupNoOfBits); - col.setAutoIncrement(aAutoIncrement); - col.setDefaultValue(aDefaultValue != 0 ? aDefaultValue : ""); - - m_currentTable->addColumn(col); - return 0; -} - -/****************************************************************************** -void release(); - -Remark: Release all objects connected to the schemaop object. -******************************************************************************/ -void -NdbSchemaOp::release(){ -}//NdbSchemaOp::release() - -/****************************************************************************** -int sendRec() - -Return Value: Return 0 : send was succesful. - Return -1: In all other case. -Parameters: -Remark: Send and receive signals for schema transaction based on state -******************************************************************************/ -int -NdbSchemaOp::sendRec(){ - int retVal = 0; - if(m_currentTable == 0){ - retVal = -1; - } else { - retVal = theNdb->getDictionary()->createTable(* m_currentTable); - delete m_currentTable; - theSchemaCon->theError.code = theNdb->getDictionary()->getNdbError().code; - } - - return retVal; -}//NdbSchemaOp::sendRec() - -/****************************************************************************** -int init(); - -Return Value: Return 0 : init was successful. - Return -1: In all other case. -Remark: Initiates SchemaOp record after allocation. -******************************************************************************/ -int -NdbSchemaOp::init(NdbSchemaCon* aSchemaCon) -{ - theSchemaCon = aSchemaCon; - return 0; -}//NdbSchemaOp::init() diff --git a/ndb/src/ndbapi/NdbUtil.hpp b/ndb/src/ndbapi/NdbUtil.hpp index 6a82af85987..80fc15ddd8c 100644 --- a/ndb/src/ndbapi/NdbUtil.hpp +++ b/ndb/src/ndbapi/NdbUtil.hpp @@ -30,7 +30,6 @@ Comment: #define NdbUtil_H #include <ndb_global.h> -#include "AttrType.hpp" class NdbApiSignal; class NdbOperation; diff --git a/ndb/src/ndbapi/Ndberr.cpp b/ndb/src/ndbapi/Ndberr.cpp index faa2f00cfce..a8b968da03f 100644 --- a/ndb/src/ndbapi/Ndberr.cpp +++ b/ndb/src/ndbapi/Ndberr.cpp @@ -18,9 +18,9 @@ #include <NdbError.hpp> #include "NdbImpl.hpp" #include "NdbDictionaryImpl.hpp" -#include <NdbSchemaCon.hpp> #include <NdbOperation.hpp> #include <NdbConnection.hpp> +#include <NdbBlob.hpp> static void @@ -67,9 +67,9 @@ NdbOperation::getNdbError() const { return theError; } -const -NdbError & -NdbSchemaCon::getNdbError() const { +const +NdbError & +NdbBlob::getNdbError() const { update(theError); return theError; } diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index 696dfe68e40..a05eb4c54c3 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -16,10 +16,9 @@ #include "NdbApiSignal.hpp" -#include "AttrType.hpp" #include "NdbImpl.hpp" -#include "NdbSchemaOp.hpp" -#include "NdbSchemaCon.hpp" +//#include "NdbSchemaOp.hpp" +//#include "NdbSchemaCon.hpp" #include "NdbOperation.hpp" #include "NdbIndexOperation.hpp" #include "NdbScanReceiver.hpp" @@ -42,13 +41,12 @@ /****************************************************************************** - * int init( int aNrOfCon, int aNrOfOp ); + * int init( int aMaxNoOfTransactions ); * * Return Value: Return 0 : init was successful. * Return -1: In all other case. - * Parameters: aNrOfCon : Number of connections offered to the application. - * aNrOfOp : Number of operations offered to the application. - * Remark: Create pointers and idle list Synchronous. + * Parameters: aMaxNoOfTransactions : Max number of simultaneous transations + * Remark: Create pointers and idle list Synchronous. ****************************************************************************/ int Ndb::init(int aMaxNoOfTransactions) @@ -90,7 +88,7 @@ Ndb::init(int aMaxNoOfTransactions) theMyRef = numberToRef(theNdbBlockNumber, theNode); for (i = 1; i < MAX_NDB_NODES; i++){ - if (theFacade->getIsNodeDefined(i)){ + if (theFacade->getIsDbNode(i)){ theDBnodes[theNoOfDBnodes] = i; theNoOfDBnodes++; } @@ -254,8 +252,9 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) for (int i = tNoSentTransactions - 1; i >= 0; i--) { NdbConnection* localCon = theSentTransactionsArray[i]; if (localCon->getConnectedNodeId() == aNodeId ) { - const SendStatusType sendStatus = localCon->theSendStatus; - if (sendStatus == sendTC_OP || sendStatus == sendTC_COMMIT) { + const NdbConnection::SendStatusType sendStatus = localCon->theSendStatus; + if (sendStatus == NdbConnection::sendTC_OP || + sendStatus == NdbConnection::sendTC_COMMIT) { /* A transaction was interrupted in the prepare phase by a node failure. Since the transaction was not found in the phase @@ -263,13 +262,13 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) we report a normal node failure abort. */ localCon->setOperationErrorCodeAbort(4010); - localCon->theCompletionStatus = CompletedFailure; - } else if (sendStatus == sendTC_ROLLBACK) { + localCon->theCompletionStatus = NdbConnection::CompletedFailure; + } else if (sendStatus == NdbConnection::sendTC_ROLLBACK) { /* We aimed for abort and abort we got even if it was by a node failure. We will thus report it as a success. */ - localCon->theCompletionStatus = CompletedSuccess; + localCon->theCompletionStatus = NdbConnection::CompletedSuccess; } else { #ifdef VM_TRACE printState("abortTransactionsAfterNodeFailure %x", this); @@ -281,7 +280,7 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) intact since the node was failing and they were aborted. Thus we set commit state to Aborted and set state to release on close. */ - localCon->theCommitStatus = Aborted; + localCon->theCommitStatus = NdbConnection::Aborted; localCon->theReleaseOnClose = true; completedTransaction(localCon); }//if @@ -328,7 +327,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_OP)) { + (tCon->theSendStatus == NdbConnection::sendTC_OP)) { tReturnCode = tCon->receiveTCKEYCONF(keyConf, aSignal->getLength()); if (tReturnCode != -1) { completedTransaction(tCon); @@ -356,7 +355,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if (tCon->theSendStatus == sendTC_OP) { + if (tCon->theSendStatus == NdbConnection::sendTC_OP) { tReturnCode = tOp->receiveREAD_CONF(tDataPtr, aSignal->getLength()); if (tReturnCode != -1) { @@ -381,7 +380,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if (tCon->theSendStatus == sendTC_OP) { + if (tCon->theSendStatus == NdbConnection::sendTC_OP) { tReturnCode = tOp->receiveTRANSID_AI(tDataPtr, aSignal->getLength()); if (tReturnCode != -1) { @@ -398,7 +397,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if (tCon->theSendStatus == sendTC_OP) { + if (tCon->theSendStatus == NdbConnection::sendTC_OP) { tReturnCode = tOp->receiveTRANSID_AI(tDataPtr, aSignal->getLength()); if (tReturnCode != -1) { @@ -442,8 +441,8 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if ((tCon->theSendStatus == sendTC_OP) || - (tCon->theSendStatus == sendTC_COMMIT)) { + if ((tCon->theSendStatus == NdbConnection::sendTC_OP) || + (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) { tReturnCode = tCon->receiveTCKEY_FAILCONF(failConf); if (tReturnCode != -1) { completedTransaction(tCon); @@ -469,8 +468,8 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if ((tCon->theSendStatus == sendTC_OP) || - (tCon->theSendStatus == sendTC_ROLLBACK)) { + if ((tCon->theSendStatus == NdbConnection::sendTC_OP) || + (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) { tReturnCode = tCon->receiveTCKEY_FAILREF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -490,7 +489,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tOp->checkMagicNumber() == 0) { tCon = tOp->theNdbCon; if (tCon != NULL) { - if (tCon->theSendStatus == sendTC_OP) { + if (tCon->theSendStatus == NdbConnection::sendTC_OP) { tReturnCode = tOp->receiveTCKEYREF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -512,7 +511,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_COMMIT)) { + (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) { tReturnCode = tCon->receiveTC_COMMITCONF(commitConf); if (tReturnCode != -1) { completedTransaction(tCon); @@ -537,7 +536,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_COMMIT)) { + (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) { tReturnCode = tCon->receiveTC_COMMITREF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -553,7 +552,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_ROLLBACK)) { + (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) { tReturnCode = tCon->receiveTCROLLBACKCONF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -568,7 +567,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_ROLLBACK)) { + (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) { tReturnCode = tCon->receiveTCROLLBACKREF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -789,7 +788,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) const BlockReference aTCRef = aSignal->theSendersBlockRef; tCon = void2con(tFirstDataPtr); if ((tCon->checkMagicNumber() == 0) && - (tCon->theSendStatus == sendTC_OP)) { + (tCon->theSendStatus == NdbConnection::sendTC_OP)) { tReturnCode = tCon->receiveTCINDXCONF(indxConf, aSignal->getLength()); if (tReturnCode != -1) { completedTransaction(tCon); @@ -812,7 +811,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3]) if (tIndexOp->checkMagicNumber() == 0) { tCon = tIndexOp->theNdbCon; if (tCon != NULL) { - if (tCon->theSendStatus == sendTC_OP) { + if (tCon->theSendStatus == NdbConnection::sendTC_OP) { tReturnCode = tIndexOp->receiveTCINDXREF(aSignal); if (tReturnCode != -1) { completedTransaction(tCon); @@ -866,7 +865,8 @@ Ndb::completedTransaction(NdbConnection* aCon) Uint32 tTransArrayIndex = aCon->theTransArrayIndex; Uint32 tNoSentTransactions = theNoOfSentTransactions; Uint32 tNoCompletedTransactions = theNoOfCompletedTransactions; - if ((tNoSentTransactions > 0) && (aCon->theListState == InSendList) && + if ((tNoSentTransactions > 0) && + (aCon->theListState == NdbConnection::InSendList) && (tTransArrayIndex < tNoSentTransactions)) { NdbConnection* tMoveCon = theSentTransactionsArray[tNoSentTransactions - 1]; @@ -880,7 +880,7 @@ Ndb::completedTransaction(NdbConnection* aCon) theNoOfCompletedTransactions = tNoCompletedTransactions + 1; theNoOfSentTransactions = tNoSentTransactions - 1; - aCon->theListState = InCompletedList; + aCon->theListState = NdbConnection::InCompletedList; aCon->handleExecuteCompletion(); if ((theMinNoOfEventsToWakeUp != 0) && (theNoOfCompletedTransactions >= theMinNoOfEventsToWakeUp)) { @@ -915,7 +915,7 @@ Ndb::reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfCompletedTrans) NdbAsynchCallback aCallback = aCopyArray[i]->theCallbackFunction; int tResult = 0; if (aCallback != NULL) { - if (aCopyArray[i]->theReturnStatus == ReturnFailure) { + if (aCopyArray[i]->theReturnStatus == NdbConnection::ReturnFailure) { tResult = -1; }//if (*aCallback)(tResult, aCopyArray[i], anyObject); @@ -939,13 +939,13 @@ Ndb::pollCompleted(NdbConnection** aCopyArray) if (tNoCompletedTransactions > 0) { for (i = 0; i < tNoCompletedTransactions; i++) { aCopyArray[i] = theCompletedTransactionsArray[i]; - if (aCopyArray[i]->theListState != InCompletedList) { + if (aCopyArray[i]->theListState != NdbConnection::InCompletedList) { ndbout << "pollCompleted error "; ndbout << aCopyArray[i]->theListState << endl; abort(); }//if theCompletedTransactionsArray[i] = NULL; - aCopyArray[i]->theListState = NotInList; + aCopyArray[i]->theListState = NdbConnection::NotInList; }//for }//if theNoOfCompletedTransactions = 0; @@ -967,8 +967,8 @@ Ndb::check_send_timeout() a_con->printState(); #endif a_con->setOperationErrorCodeAbort(4012); - a_con->theCommitStatus = Aborted; - a_con->theCompletionStatus = CompletedFailure; + a_con->theCommitStatus = NdbConnection::Aborted; + a_con->theCompletionStatus = NdbConnection::CompletedFailure; a_con->handleExecuteCompletion(); remove_sent_list(i); insert_completed_list(a_con); @@ -997,7 +997,7 @@ Ndb::insert_completed_list(NdbConnection* a_con) Uint32 no_of_comp = theNoOfCompletedTransactions; theCompletedTransactionsArray[no_of_comp] = a_con; theNoOfCompletedTransactions = no_of_comp + 1; - a_con->theListState = InCompletedList; + a_con->theListState = NdbConnection::InCompletedList; a_con->theTransArrayIndex = no_of_comp; return no_of_comp; } @@ -1008,7 +1008,7 @@ Ndb::insert_sent_list(NdbConnection* a_con) Uint32 no_of_sent = theNoOfSentTransactions; theSentTransactionsArray[no_of_sent] = a_con; theNoOfSentTransactions = no_of_sent + 1; - a_con->theListState = InSendList; + a_con->theListState = NdbConnection::InSendList; a_con->theTransArrayIndex = no_of_sent; return no_of_sent; } @@ -1046,10 +1046,10 @@ Ndb::sendPrepTrans(int forceSend) if ((tp->getNodeSequence(node_id) == a_con->theNodeSequence) && tp->get_node_alive(node_id) || (tp->get_node_stopping(node_id) && - ((a_con->theSendStatus == sendABORT) || - (a_con->theSendStatus == sendABORTfail) || - (a_con->theSendStatus == sendCOMMITstate) || - (a_con->theSendStatus == sendCompleted)))) { + ((a_con->theSendStatus == NdbConnection::sendABORT) || + (a_con->theSendStatus == NdbConnection::sendABORTfail) || + (a_con->theSendStatus == NdbConnection::sendCOMMITstate) || + (a_con->theSendStatus == NdbConnection::sendCompleted)))) { /* We will send if 1) Node is alive and sequences are correct OR @@ -1081,13 +1081,13 @@ Ndb::sendPrepTrans(int forceSend) again and will thus set the state to Aborted to avoid a more or less eternal loop of tries. */ - if (a_con->theSendStatus == sendOperations) { + if (a_con->theSendStatus == NdbConnection::sendOperations) { a_con->setOperationErrorCodeAbort(4021); - a_con->theCommitStatus = NeedAbort; + a_con->theCommitStatus = NdbConnection::NeedAbort; TRACE_DEBUG("Send buffer full and sendOperations"); } else { a_con->setOperationErrorCodeAbort(4026); - a_con->theCommitStatus = Aborted; + a_con->theCommitStatus = NdbConnection::Aborted; TRACE_DEBUG("Send buffer full, set state to Aborted"); }//if }//if @@ -1104,7 +1104,7 @@ Ndb::sendPrepTrans(int forceSend) */ TRACE_DEBUG("Abort a transaction when stopping a node"); a_con->setOperationErrorCodeAbort(4023); - a_con->theCommitStatus = NeedAbort; + a_con->theCommitStatus = NdbConnection::NeedAbort; } else { /* The node is hard dead and we cannot continue. We will also release @@ -1114,10 +1114,10 @@ Ndb::sendPrepTrans(int forceSend) a_con->setOperationErrorCodeAbort(4025); a_con->theReleaseOnClose = true; a_con->theTransactionIsStarted = false; - a_con->theCommitStatus = Aborted; + a_con->theCommitStatus = NdbConnection::Aborted; }//if }//if - a_con->theCompletionStatus = CompletedFailure; + a_con->theCompletionStatus = NdbConnection::CompletedFailure; a_con->handleExecuteCompletion(); insert_completed_list(a_con); }//for diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index be7acc48d7a..f451ba885d4 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -15,10 +15,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <ndb_global.h> + #include "NdbApiSignal.hpp" #include "NdbImpl.hpp" -#include "NdbSchemaOp.hpp" -#include "NdbSchemaCon.hpp" +//#include "NdbSchemaOp.hpp" +//#include "NdbSchemaCon.hpp" #include "NdbOperation.hpp" #include "NdbConnection.hpp" #include "NdbRecAttr.hpp" @@ -54,7 +56,7 @@ Ndb(const char* aDataBase); Parameters: aDataBase : Name of the database. Remark: Connect to the database. ***************************************************************************/ -Ndb::Ndb( const char* aDataBase , const char* aDataBaseSchema) : +Ndb::Ndb( const char* aDataBase , const char* aSchema) : theNdbObjectIdMap(0), thePreparedTransactionsArray(NULL), theSentTransactionsArray(NULL), @@ -72,8 +74,8 @@ Ndb::Ndb( const char* aDataBase , const char* aDataBaseSchema) : theOpIdleList(NULL), theScanOpIdleList(NULL), theIndexOpIdleList(NULL), - theSchemaConIdleList(NULL), - theSchemaConToNdbList(NULL), +// theSchemaConIdleList(NULL), +// theSchemaConToNdbList(NULL), theTransactionList(NULL), theConnectionArray(NULL), theRecAttrIdleList(NULL), @@ -83,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), @@ -92,6 +95,8 @@ Ndb::Ndb( const char* aDataBase , const char* aDataBaseSchema) : theNdbBlockNumber(-1), theInitState(NotConstructed) { + fullyQualifiedNames = true; + cgetSignals =0; cfreeSignals = 0; cnewSignals = 0; @@ -116,28 +121,22 @@ Ndb::Ndb( const char* aDataBase , const char* aDataBaseSchema) : theLastTupleId[i] = 0; }//for - if (aDataBase) - strncpy(theDataBase, aDataBase, NDB_MAX_DATABASE_NAME_SIZE); - else - memset(theDataBase, 0, sizeof(theDataBase)); - strncpy(theDataBaseSchema, aDataBaseSchema, NDB_MAX_SCHEMA_NAME_SIZE); - // Prepare prefix for faster operations - uint db_len = MIN(strlen(theDataBase), NDB_MAX_DATABASE_NAME_SIZE - 1); - uint schema_len = - MIN(strlen(theDataBaseSchema), NDB_MAX_SCHEMA_NAME_SIZE - 1); - strncpy(prefixName, theDataBase, NDB_MAX_DATABASE_NAME_SIZE - 1); - prefixName[db_len] = '/'; - strncpy(prefixName+db_len+1, theDataBaseSchema, - NDB_MAX_SCHEMA_NAME_SIZE - 1); - prefixName[db_len+schema_len+1] = '/'; - prefixName[db_len+schema_len+2] = '\0'; - prefixEnd = prefixName + db_len+schema_len + 2; + snprintf(theDataBase, sizeof(theDataBase), "%s", + aDataBase ? aDataBase : ""); + snprintf(theDataBaseSchema, sizeof(theDataBaseSchema), "%s", + aSchema ? aSchema : ""); + + int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + theDataBase, table_name_separator, + theDataBaseSchema, table_name_separator); + prefixEnd = prefixName + (len < sizeof(prefixName) ? len : + sizeof(prefixName) - 1); NdbMutex_Lock(&createNdbMutex); TransporterFacade * m_facade = 0; if(theNoOfNdbObjects == 0){ - if ((m_facade = TransporterFacade::start_instance(0,ndbConnectString)) == 0) + if ((m_facade = TransporterFacade::start_instance(ndbConnectString)) == 0) theInitState = InitConfigError; } else { m_facade = TransporterFacade::instance(); @@ -207,8 +206,8 @@ Ndb::~Ndb() NdbMutex_Unlock(&createNdbMutex); - if (theSchemaConToNdbList != NULL) - closeSchemaTransaction(theSchemaConToNdbList); +// if (theSchemaConToNdbList != NULL) +// closeSchemaTransaction(theSchemaConToNdbList); while ( theConIdleList != NULL ) freeNdbCon(); while ( theSignalIdleList != NULL ) @@ -231,6 +230,8 @@ Ndb::~Ndb() freeNdbCall(); while (theScanList != NULL) freeNdbScanRec(); + while (theNdbBlobIdleList != NULL) + freeNdbBlob(); releaseTransactionArrays(); startTransactionNodeSelectionData.release(); diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index 3839cc3291b..e557fdc0a5f 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -16,8 +16,8 @@ #include <NdbOut.hpp> #include "Ndb.hpp" -#include "NdbSchemaOp.hpp" -#include "NdbSchemaCon.hpp" +//#include "NdbSchemaOp.hpp" +//#include "NdbSchemaCon.hpp" #include "NdbOperation.hpp" #include "NdbScanOperation.hpp" #include "NdbIndexOperation.hpp" @@ -27,6 +27,7 @@ #include "NdbScanReceiver.hpp" #include "NdbUtil.hpp" #include "API.hpp" +#include "NdbBlob.hpp" void Ndb::checkFailedNode() @@ -104,7 +105,7 @@ Ndb::createConIdleList(int aNrOfCon) tNdbCon->next(theConIdleList); theConIdleList = tNdbCon; } - tNdbCon->Status(NotConnected); + tNdbCon->Status(NdbConnection::NotConnected); } theNoOfAllocatedTransactions = aNrOfCon; return aNrOfCon; @@ -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); @@ -770,7 +800,7 @@ Ndb::releaseConnectToNdb(NdbConnection* a_con) tSignal.setData((tConPtr = a_con->getTC_ConnectPtr()), 1); tSignal.setData(theMyRef, 2); tSignal.setData(a_con->ptr2int(), 3); - a_con->Status(DisConnecting); + a_con->Status(NdbConnection::DisConnecting); a_con->theMagicNumber = 0x37412619; int ret_code = sendRecSignal(node_id, WAIT_TC_RELEASE, diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp index f4a3ae3e87d..e725144a8f8 100644 --- a/ndb/src/ndbapi/TransporterFacade.cpp +++ b/ndb/src/ndbapi/TransporterFacade.cpp @@ -16,7 +16,6 @@ #include <ndb_global.h> #include <ndb_limits.h> -#include <AttrType.hpp> #include "TransporterFacade.hpp" #include "ClusterMgr.hpp" #include <IPCConfig.hpp> @@ -29,6 +28,8 @@ #include "API.hpp" #include <ConfigRetriever.hpp> +#include <mgmapi_config_parameters.h> +#include <mgmapi_configuration.hpp> #include <NdbConfig.h> #include <ndb_version.h> #include <SignalLoggerManager.hpp> @@ -332,39 +333,40 @@ atexit_stop_instance(){ * Which is protected by a mutex */ TransporterFacade* -TransporterFacade::start_instance(Properties* props, const char *connectString) -{ - bool ownProps = false; - if (props == NULL) { - // TransporterFacade used from API get config from mgmt srvr - ConfigRetriever configRetriever; - configRetriever.setConnectString(connectString); - props = configRetriever.getConfig("API", NDB_VERSION); - if (props == 0) { - ndbout << "Configuration error: "; - const char* erString = configRetriever.getErrorString(); - if (erString == 0) { - erString = "No error specified!"; - } - ndbout << erString << endl; - return NULL; +TransporterFacade::start_instance(const char * connectString){ + + // TransporterFacade used from API get config from mgmt srvr + ConfigRetriever configRetriever; + configRetriever.setConnectString(connectString); + ndb_mgm_configuration * props = configRetriever.getConfig(NDB_VERSION, + NODE_TYPE_API); + if (props == 0) { + ndbout << "Configuration error: "; + const char* erString = configRetriever.getErrorString(); + if (erString == 0) { + erString = "No error specified!"; } - props->put("LocalNodeId", configRetriever.getOwnNodeId()); - props->put("LocalNodeType", "API"); - - ownProps = true; + ndbout << erString << endl; + return 0; } - TransporterFacade* tf = new TransporterFacade(); + const int nodeId = configRetriever.getOwnNodeId(); - if (! tf->init(props)) { + TransporterFacade * tf = start_instance(nodeId, props); + + free(props); + return tf; +} + +TransporterFacade* +TransporterFacade::start_instance(int nodeId, + const ndb_mgm_configuration* props) +{ + TransporterFacade* tf = new TransporterFacade(); + if (! tf->init(nodeId, props)) { delete tf; return NULL; } - if (ownProps) { - delete props; - } - /** * Install atexit handler */ @@ -499,61 +501,65 @@ TransporterFacade::TransporterFacade() : } bool -TransporterFacade::init(Properties* props) +TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) { - IPCConfig config(props); - - if (config.init() != 0) { - TRP_DEBUG( "IPCConfig object config failed to init()" ); - return false; - } - theOwnId = config.ownId(); - + theOwnId = nodeId; theTransporterRegistry = new TransporterRegistry(this); - if(config.configureTransporters(theTransporterRegistry) <= 0) { + + const int res = IPCConfig::configureTransporters(nodeId, + * props, + * theTransporterRegistry); + if(res <= 0){ TRP_DEBUG( "configureTransporters returned 0 or less" ); return false; } + ndb_mgm_configuration_iterator iter(* props, CFG_SECTION_NODE); + iter.first(); theClusterMgr = new ClusterMgr(* this); - theClusterMgr->init(config); - - theReceiveThread = NdbThread_Create(runReceiveResponse_C, - (void**)this, - 32768, - "ndb_receive", - NDB_THREAD_PRIO_LOW); - - theSendThread = NdbThread_Create(runSendRequest_C, - (void**)this, - 32768, - "ndb_send", - NDB_THREAD_PRIO_LOW); - - theClusterMgr->startThread(); + theClusterMgr->init(iter); /** * Unless there is a "Name", the initiated transporter is within * an NDB Cluster. (If "Name" is defined, then the transporter * is used to connect to a different system, i.e. NDB Cluster.) */ +#if 0 if (!props->contains("Name")) { - const Properties* p = 0; - if(!props->get("Node", ownId(), &p)) { +#endif + iter.first(); + if(iter.find(CFG_NODE_ID, nodeId)){ TRP_DEBUG( "Node info missing from config." ); return false; } Uint32 rank = 0; - if (p->get("ArbitrationRank", &rank) && rank > 0) { + if(!iter.get(CFG_NODE_ARBIT_RANK, &rank) && rank>0){ theArbitMgr = new ArbitMgr(* this); theArbitMgr->setRank(rank); Uint32 delay = 0; - p->get("ArbitrationDelay", &delay); + iter.get(CFG_NODE_ARBIT_DELAY, &delay); theArbitMgr->setDelay(delay); } + +#if 0 } +#endif + + theReceiveThread = NdbThread_Create(runReceiveResponse_C, + (void**)this, + 32768, + "ndb_receive", + NDB_THREAD_PRIO_LOW); + + theSendThread = NdbThread_Create(runSendRequest_C, + (void**)this, + 32768, + "ndb_send", + NDB_THREAD_PRIO_LOW); + theClusterMgr->startThread(); + #ifdef API_TRACE signalLogger.logOn(true, 0, SignalLoggerManager::LogInOut); #endif diff --git a/ndb/src/ndbapi/TransporterFacade.hpp b/ndb/src/ndbapi/TransporterFacade.hpp index d9d2dbbcf0f..4b76cbe864a 100644 --- a/ndb/src/ndbapi/TransporterFacade.hpp +++ b/ndb/src/ndbapi/TransporterFacade.hpp @@ -17,7 +17,6 @@ #ifndef TransporterFacade_H #define TransporterFacade_H -#include <AttrType.hpp> #include <kernel_types.h> #include <ndb_limits.h> #include <NdbThread.h> @@ -28,8 +27,8 @@ class ClusterMgr; class ArbitMgr; -class Properties; class IPCConfig; +struct ndb_mgm_configuration; class Ndb; class NdbApiSignal; @@ -43,15 +42,20 @@ extern "C" { void atexit_stop_instance(); } +/** + * Max number of Ndb objects in different threads. + * (Ndb objects should not be shared by different threads.) + */ class TransporterFacade { public: TransporterFacade(); virtual ~TransporterFacade(); - bool init(Properties* props); + bool init(Uint32, const ndb_mgm_configuration *); static TransporterFacade* instance(); - static TransporterFacade* start_instance(Properties* ipcConfig, const char *connectString); + static TransporterFacade* start_instance(int, const ndb_mgm_configuration*); + static TransporterFacade* start_instance(const char *connectString); static void stop_instance(); /** @@ -76,7 +80,7 @@ public: // Is node available for running transactions bool get_node_alive(NodeId nodeId) const; bool get_node_stopping(NodeId nodeId) const; - bool getIsNodeDefined(NodeId nodeId) const; + bool getIsDbNode(NodeId nodeId) const; bool getIsNodeSendable(NodeId nodeId) const; Uint32 getNodeGrp(NodeId nodeId) const; Uint32 getNodeSequence(NodeId nodeId) const; @@ -156,6 +160,8 @@ private: /** * Block number handling */ + static const unsigned MAX_NO_THREADS = 4711; + struct ThreadData { static const Uint32 ACTIVE = (1 << 16) | 1; static const Uint32 INACTIVE = (1 << 16); @@ -250,8 +256,10 @@ TransporterFacade::check_send_size(Uint32 node_id, Uint32 send_size) inline bool -TransporterFacade::getIsNodeDefined(NodeId n) const { - return theClusterMgr->getNodeInfo(n).defined; +TransporterFacade::getIsDbNode(NodeId n) const { + return + theClusterMgr->getNodeInfo(n).defined && + theClusterMgr->getNodeInfo(n).m_info.m_type == NodeInfo::DB; } inline diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index ea7cf4de426..760322d669d 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -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 diff --git a/ndb/src/ndbapi/signal-sender/SignalSender.cpp b/ndb/src/ndbapi/signal-sender/SignalSender.cpp index e642848dcee..680d0c23b4a 100644 --- a/ndb/src/ndbapi/signal-sender/SignalSender.cpp +++ b/ndb/src/ndbapi/signal-sender/SignalSender.cpp @@ -71,7 +71,7 @@ SimpleSignal::print(FILE * out){ SignalSender::SignalSender(const char * connectString){ m_cond = NdbCondition_Create(); - theFacade = TransporterFacade::start_instance(0,connectString); + theFacade = TransporterFacade::start_instance(connectString); m_blockNo = theFacade->open(this, execSignal, execNodeStatus); assert(m_blockNo > 0); } |