mirror of
https://github.com/MariaDB/server.git
synced 2025-11-15 09:02:33 +03:00
4986 lines
134 KiB
C++
4986 lines
134 KiB
C++
/* 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 "NdbDictionaryImpl.hpp"
|
|
#include "API.hpp"
|
|
#include <NdbOut.hpp>
|
|
#include "NdbApiSignal.hpp"
|
|
#include "TransporterFacade.hpp"
|
|
#include <signaldata/GetTabInfo.hpp>
|
|
#include <signaldata/DictTabInfo.hpp>
|
|
#include <signaldata/CreateTable.hpp>
|
|
#include <signaldata/CreateIndx.hpp>
|
|
#include <signaldata/CreateEvnt.hpp>
|
|
#include <signaldata/SumaImpl.hpp>
|
|
#include <signaldata/DropTable.hpp>
|
|
#include <signaldata/AlterTable.hpp>
|
|
#include <signaldata/DropIndx.hpp>
|
|
#include <signaldata/ListTables.hpp>
|
|
#include <signaldata/DropFilegroup.hpp>
|
|
#include <signaldata/CreateFilegroup.hpp>
|
|
#include <signaldata/WaitGCP.hpp>
|
|
#include <SimpleProperties.hpp>
|
|
#include <Bitmask.hpp>
|
|
#include <AttributeList.hpp>
|
|
#include <NdbEventOperation.hpp>
|
|
#include "NdbEventOperationImpl.hpp"
|
|
#include <NdbBlob.hpp>
|
|
#include "NdbBlobImpl.hpp"
|
|
#include <AttributeHeader.hpp>
|
|
#include <my_sys.h>
|
|
#include <NdbEnv.h>
|
|
#include <NdbMem.h>
|
|
#include <ndb_version.h>
|
|
|
|
#define DEBUG_PRINT 0
|
|
#define INCOMPATIBLE_VERSION -2
|
|
|
|
#define DICT_WAITFOR_TIMEOUT (7*24*60*60*1000)
|
|
|
|
#define ERR_RETURN(a,b) \
|
|
{\
|
|
DBUG_PRINT("exit", ("error %d", (a).code));\
|
|
DBUG_RETURN(b);\
|
|
}
|
|
|
|
extern Uint64 g_latest_trans_gci;
|
|
int ndb_dictionary_is_mysqld = 0;
|
|
|
|
bool
|
|
is_ndb_blob_table(const char* name, Uint32* ptab_id, Uint32* pcol_no)
|
|
{
|
|
return DictTabInfo::isBlobTableName(name, ptab_id, pcol_no);
|
|
}
|
|
|
|
bool
|
|
is_ndb_blob_table(const NdbTableImpl* t)
|
|
{
|
|
return is_ndb_blob_table(t->m_internalName.c_str());
|
|
}
|
|
|
|
//#define EVENT_DEBUG
|
|
|
|
/**
|
|
* Column
|
|
*/
|
|
NdbColumnImpl::NdbColumnImpl()
|
|
: NdbDictionary::Column(* this), m_attrId(-1), m_facade(this)
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::NdbColumnImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
NdbColumnImpl::NdbColumnImpl(NdbDictionary::Column & f)
|
|
: NdbDictionary::Column(* this), m_attrId(-1), m_facade(&f)
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::NdbColumnImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
NdbColumnImpl&
|
|
NdbColumnImpl::operator=(const NdbColumnImpl& col)
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::operator=");
|
|
DBUG_PRINT("info", ("this: %p &col: %p", this, &col));
|
|
m_attrId = col.m_attrId;
|
|
m_name = col.m_name;
|
|
m_type = col.m_type;
|
|
m_precision = col.m_precision;
|
|
m_cs = col.m_cs;
|
|
m_scale = col.m_scale;
|
|
m_length = col.m_length;
|
|
m_pk = col.m_pk;
|
|
m_distributionKey = col.m_distributionKey;
|
|
m_nullable = col.m_nullable;
|
|
m_autoIncrement = col.m_autoIncrement;
|
|
m_autoIncrementInitialValue = col.m_autoIncrementInitialValue;
|
|
m_defaultValue = col.m_defaultValue;
|
|
m_attrSize = col.m_attrSize;
|
|
m_arraySize = col.m_arraySize;
|
|
m_arrayType = col.m_arrayType;
|
|
m_storageType = col.m_storageType;
|
|
m_keyInfoPos = col.m_keyInfoPos;
|
|
if (col.m_blobTable == NULL)
|
|
m_blobTable = NULL;
|
|
else {
|
|
if (m_blobTable == NULL)
|
|
m_blobTable = new NdbTableImpl();
|
|
m_blobTable->assign(*col.m_blobTable);
|
|
}
|
|
m_column_no = col.m_column_no;
|
|
// Do not copy m_facade !!
|
|
|
|
DBUG_RETURN(*this);
|
|
}
|
|
|
|
void
|
|
NdbColumnImpl::init(Type t)
|
|
{
|
|
// do not use default_charset_info as it may not be initialized yet
|
|
// use binary collation until NDB tests can handle charsets
|
|
CHARSET_INFO* default_cs = &my_charset_bin;
|
|
m_type = t;
|
|
switch (m_type) {
|
|
case Tinyint:
|
|
case Tinyunsigned:
|
|
case Smallint:
|
|
case Smallunsigned:
|
|
case Mediumint:
|
|
case Mediumunsigned:
|
|
case Int:
|
|
case Unsigned:
|
|
case Bigint:
|
|
case Bigunsigned:
|
|
case Float:
|
|
case Double:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Olddecimal:
|
|
case Olddecimalunsigned:
|
|
case Decimal:
|
|
case Decimalunsigned:
|
|
m_precision = 10;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Char:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = default_cs;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Varchar:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = default_cs;
|
|
m_arrayType = NDB_ARRAYTYPE_SHORT_VAR;
|
|
break;
|
|
case Binary:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Varbinary:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_SHORT_VAR;
|
|
break;
|
|
case Datetime:
|
|
case Date:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Blob:
|
|
m_precision = 256;
|
|
m_scale = 8000;
|
|
m_length = 4;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Text:
|
|
m_precision = 256;
|
|
m_scale = 8000;
|
|
m_length = 4;
|
|
m_cs = default_cs;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Time:
|
|
case Year:
|
|
case Timestamp:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Bit:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1;
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_FIXED;
|
|
break;
|
|
case Longvarchar:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1; // legal
|
|
m_cs = default_cs;
|
|
m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
|
|
break;
|
|
case Longvarbinary:
|
|
m_precision = 0;
|
|
m_scale = 0;
|
|
m_length = 1; // legal
|
|
m_cs = NULL;
|
|
m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
|
|
break;
|
|
default:
|
|
case Undefined:
|
|
assert(false);
|
|
break;
|
|
}
|
|
m_pk = false;
|
|
m_nullable = false;
|
|
m_distributionKey = false;
|
|
m_keyInfoPos = 0;
|
|
// next 2 are set at run time
|
|
m_attrSize = 0;
|
|
m_arraySize = 0;
|
|
m_autoIncrement = false;
|
|
m_autoIncrementInitialValue = 1;
|
|
m_blobTable = NULL;
|
|
m_storageType = NDB_STORAGETYPE_MEMORY;
|
|
#ifdef VM_TRACE
|
|
if(NdbEnv_GetEnv("NDB_DEFAULT_DISK", (char *)0, 0))
|
|
m_storageType = NDB_STORAGETYPE_DISK;
|
|
#endif
|
|
}
|
|
|
|
NdbColumnImpl::~NdbColumnImpl()
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::~NdbColumnImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
if (m_blobTable != NULL)
|
|
delete m_blobTable;
|
|
m_blobTable = NULL;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
bool
|
|
NdbColumnImpl::equal(const NdbColumnImpl& col) const
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::equal");
|
|
DBUG_PRINT("info", ("this: %p &col: %p", this, &col));
|
|
if(strcmp(m_name.c_str(), col.m_name.c_str()) != 0){
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(m_type != col.m_type){
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(m_pk != col.m_pk){
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(m_nullable != col.m_nullable){
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_pk) {
|
|
if ((bool)m_distributionKey != (bool)col.m_distributionKey) {
|
|
DBUG_RETURN(false);
|
|
}
|
|
}
|
|
if (m_precision != col.m_precision ||
|
|
m_scale != col.m_scale ||
|
|
m_length != col.m_length ||
|
|
m_cs != col.m_cs) {
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_autoIncrement != col.m_autoIncrement){
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(strcmp(m_defaultValue.c_str(), col.m_defaultValue.c_str()) != 0){
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if (m_arrayType != col.m_arrayType || m_storageType != col.m_storageType){
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
DBUG_RETURN(true);
|
|
}
|
|
|
|
NdbDictionary::Column *
|
|
NdbColumnImpl::create_pseudo(const char * name){
|
|
NdbDictionary::Column * col = new NdbDictionary::Column();
|
|
col->setName(name);
|
|
if(!strcmp(name, "NDB$FRAGMENT")){
|
|
col->setType(NdbDictionary::Column::Unsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::FRAGMENT;
|
|
col->m_impl.m_attrSize = 4;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$FRAGMENT_MEMORY")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::FRAGMENT_MEMORY;
|
|
col->m_impl.m_attrSize = 8;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$ROW_COUNT")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::ROW_COUNT;
|
|
col->m_impl.m_attrSize = 8;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$COMMIT_COUNT")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::COMMIT_COUNT;
|
|
col->m_impl.m_attrSize = 8;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$ROW_SIZE")){
|
|
col->setType(NdbDictionary::Column::Unsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::ROW_SIZE;
|
|
col->m_impl.m_attrSize = 4;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$RANGE_NO")){
|
|
col->setType(NdbDictionary::Column::Unsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::RANGE_NO;
|
|
col->m_impl.m_attrSize = 4;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$DISK_REF")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::DISK_REF;
|
|
col->m_impl.m_attrSize = 8;
|
|
col->m_impl.m_arraySize = 1;
|
|
} else if(!strcmp(name, "NDB$RECORDS_IN_RANGE")){
|
|
col->setType(NdbDictionary::Column::Unsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::RECORDS_IN_RANGE;
|
|
col->m_impl.m_attrSize = 4;
|
|
col->m_impl.m_arraySize = 4;
|
|
} else if(!strcmp(name, "NDB$ROWID")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::ROWID;
|
|
col->m_impl.m_attrSize = 4;
|
|
col->m_impl.m_arraySize = 2;
|
|
} else if(!strcmp(name, "NDB$ROW_GCI")){
|
|
col->setType(NdbDictionary::Column::Bigunsigned);
|
|
col->m_impl.m_attrId = AttributeHeader::ROW_GCI;
|
|
col->m_impl.m_attrSize = 8;
|
|
col->m_impl.m_arraySize = 1;
|
|
col->m_impl.m_nullable = true;
|
|
} else {
|
|
abort();
|
|
}
|
|
col->m_impl.m_storageType = NDB_STORAGETYPE_MEMORY;
|
|
return col;
|
|
}
|
|
|
|
/**
|
|
* NdbTableImpl
|
|
*/
|
|
|
|
NdbTableImpl::NdbTableImpl()
|
|
: NdbDictionary::Table(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::UserTable), m_facade(this)
|
|
{
|
|
DBUG_ENTER("NdbTableImpl::NdbTableImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
NdbTableImpl::NdbTableImpl(NdbDictionary::Table & f)
|
|
: NdbDictionary::Table(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::UserTable), m_facade(&f)
|
|
{
|
|
DBUG_ENTER("NdbTableImpl::NdbTableImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
NdbTableImpl::~NdbTableImpl()
|
|
{
|
|
DBUG_ENTER("NdbTableImpl::~NdbTableImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
if (m_index != 0) {
|
|
delete m_index;
|
|
m_index = 0;
|
|
}
|
|
for (unsigned i = 0; i < m_columns.size(); i++)
|
|
delete m_columns[i];
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbTableImpl::init(){
|
|
m_changeMask= 0;
|
|
m_id= RNIL;
|
|
m_version = ~0;
|
|
m_status = NdbDictionary::Object::Invalid;
|
|
m_type = NdbDictionary::Object::TypeUndefined;
|
|
m_primaryTableId= RNIL;
|
|
m_internalName.clear();
|
|
m_externalName.clear();
|
|
m_newExternalName.clear();
|
|
m_mysqlName.clear();
|
|
m_frm.clear();
|
|
m_newFrm.clear();
|
|
m_ts_name.clear();
|
|
m_new_ts_name.clear();
|
|
m_ts.clear();
|
|
m_new_ts.clear();
|
|
m_fd.clear();
|
|
m_new_fd.clear();
|
|
m_range.clear();
|
|
m_new_range.clear();
|
|
m_fragmentType= NdbDictionary::Object::FragAllSmall;
|
|
m_hashValueMask= 0;
|
|
m_hashpointerValue= 0;
|
|
m_linear_flag= true;
|
|
m_primaryTable.clear();
|
|
m_max_rows = 0;
|
|
m_default_no_part_flag = 1;
|
|
m_logging= true;
|
|
m_row_gci = true;
|
|
m_row_checksum = true;
|
|
m_kvalue= 6;
|
|
m_minLoadFactor= 78;
|
|
m_maxLoadFactor= 80;
|
|
m_keyLenInWords= 0;
|
|
m_fragmentCount= 0;
|
|
m_index= NULL;
|
|
m_indexType= NdbDictionary::Object::TypeUndefined;
|
|
m_noOfKeys= 0;
|
|
m_noOfDistributionKeys= 0;
|
|
m_noOfBlobs= 0;
|
|
m_replicaCount= 0;
|
|
m_tablespace_name.clear();
|
|
m_tablespace_id = ~0;
|
|
m_tablespace_version = ~0;
|
|
}
|
|
|
|
bool
|
|
NdbTableImpl::equal(const NdbTableImpl& obj) const
|
|
{
|
|
DBUG_ENTER("NdbTableImpl::equal");
|
|
if ((m_internalName.c_str() == NULL) ||
|
|
(strcmp(m_internalName.c_str(), "") == 0) ||
|
|
(obj.m_internalName.c_str() == NULL) ||
|
|
(strcmp(obj.m_internalName.c_str(), "") == 0))
|
|
{
|
|
// Shallow equal
|
|
if(strcmp(getName(), obj.getName()) != 0)
|
|
{
|
|
DBUG_PRINT("info",("name %s != %s",getName(),obj.getName()));
|
|
DBUG_RETURN(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Deep equal
|
|
if(strcmp(m_internalName.c_str(), obj.m_internalName.c_str()) != 0)
|
|
{
|
|
DBUG_PRINT("info",("m_internalName %s != %s",
|
|
m_internalName.c_str(),obj.m_internalName.c_str()));
|
|
DBUG_RETURN(false);
|
|
}
|
|
}
|
|
if (m_frm.length() != obj.m_frm.length() ||
|
|
(memcmp(m_frm.get_data(), obj.m_frm.get_data(), m_frm.length())))
|
|
{
|
|
DBUG_PRINT("info",("m_frm not equal"));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_fd.length() != obj.m_fd.length() ||
|
|
(memcmp(m_fd.get_data(), obj.m_fd.get_data(), m_fd.length())))
|
|
{
|
|
DBUG_PRINT("info",("m_fd not equal"));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_ts.length() != obj.m_ts.length() ||
|
|
(memcmp(m_ts.get_data(), obj.m_ts.get_data(), m_ts.length())))
|
|
{
|
|
DBUG_PRINT("info",("m_ts not equal"));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_range.length() != obj.m_range.length() ||
|
|
(memcmp(m_range.get_data(), obj.m_range.get_data(), m_range.length())))
|
|
{
|
|
DBUG_PRINT("info",("m_range not equal"));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(m_fragmentType != obj.m_fragmentType)
|
|
{
|
|
DBUG_PRINT("info",("m_fragmentType %d != %d",m_fragmentType,
|
|
obj.m_fragmentType));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(m_columns.size() != obj.m_columns.size())
|
|
{
|
|
DBUG_PRINT("info",("m_columns.size %d != %d",m_columns.size(),
|
|
obj.m_columns.size()));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
for(unsigned i = 0; i<obj.m_columns.size(); i++)
|
|
{
|
|
if(!m_columns[i]->equal(* obj.m_columns[i]))
|
|
{
|
|
DBUG_PRINT("info",("m_columns [%d] != [%d]",i,i));
|
|
DBUG_RETURN(false);
|
|
}
|
|
}
|
|
|
|
if(m_linear_flag != obj.m_linear_flag)
|
|
{
|
|
DBUG_PRINT("info",("m_linear_flag %d != %d",m_linear_flag,
|
|
obj.m_linear_flag));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_max_rows != obj.m_max_rows)
|
|
{
|
|
DBUG_PRINT("info",("m_max_rows %d != %d",(int32)m_max_rows,
|
|
(int32)obj.m_max_rows));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_default_no_part_flag != obj.m_default_no_part_flag)
|
|
{
|
|
DBUG_PRINT("info",("m_default_no_part_flag %d != %d",m_default_no_part_flag,
|
|
obj.m_default_no_part_flag));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_logging != obj.m_logging)
|
|
{
|
|
DBUG_PRINT("info",("m_logging %d != %d",m_logging,obj.m_logging));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_row_gci != obj.m_row_gci)
|
|
{
|
|
DBUG_PRINT("info",("m_row_gci %d != %d",m_row_gci,obj.m_row_gci));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_row_checksum != obj.m_row_checksum)
|
|
{
|
|
DBUG_PRINT("info",("m_row_checksum %d != %d",m_row_checksum,
|
|
obj.m_row_checksum));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_kvalue != obj.m_kvalue)
|
|
{
|
|
DBUG_PRINT("info",("m_kvalue %d != %d",m_kvalue,obj.m_kvalue));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_minLoadFactor != obj.m_minLoadFactor)
|
|
{
|
|
DBUG_PRINT("info",("m_minLoadFactor %d != %d",m_minLoadFactor,
|
|
obj.m_minLoadFactor));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_maxLoadFactor != obj.m_maxLoadFactor)
|
|
{
|
|
DBUG_PRINT("info",("m_maxLoadFactor %d != %d",m_maxLoadFactor,
|
|
obj.m_maxLoadFactor));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_tablespace_id != obj.m_tablespace_id)
|
|
{
|
|
DBUG_PRINT("info",("m_tablespace_id %d != %d",m_tablespace_id,
|
|
obj.m_tablespace_id));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_tablespace_version != obj.m_tablespace_version)
|
|
{
|
|
DBUG_PRINT("info",("m_tablespace_version %d != %d",m_tablespace_version,
|
|
obj.m_tablespace_version));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_id != obj.m_id)
|
|
{
|
|
DBUG_PRINT("info",("m_id %d != %d",m_id,obj.m_id));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_version != obj.m_version)
|
|
{
|
|
DBUG_PRINT("info",("m_version %d != %d",m_version,obj.m_version));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if(m_type != obj.m_type)
|
|
{
|
|
DBUG_PRINT("info",("m_type %d != %d",m_type,obj.m_type));
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
if (m_type == NdbDictionary::Object::UniqueHashIndex ||
|
|
m_type == NdbDictionary::Object::OrderedIndex)
|
|
{
|
|
if(m_primaryTableId != obj.m_primaryTableId)
|
|
{
|
|
DBUG_PRINT("info",("m_primaryTableId %d != %d",m_primaryTableId,
|
|
obj.m_primaryTableId));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if (m_indexType != obj.m_indexType)
|
|
{
|
|
DBUG_PRINT("info",("m_indexType %d != %d",m_indexType,obj.m_indexType));
|
|
DBUG_RETURN(false);
|
|
}
|
|
if(strcmp(m_primaryTable.c_str(), obj.m_primaryTable.c_str()) != 0)
|
|
{
|
|
DBUG_PRINT("info",("m_primaryTable %s != %s",
|
|
m_primaryTable.c_str(),obj.m_primaryTable.c_str()));
|
|
DBUG_RETURN(false);
|
|
}
|
|
}
|
|
DBUG_RETURN(true);
|
|
}
|
|
|
|
void
|
|
NdbTableImpl::assign(const NdbTableImpl& org)
|
|
{
|
|
DBUG_ENTER("NdbColumnImpl::assign");
|
|
DBUG_PRINT("info", ("this: %p &org: %p", this, &org));
|
|
/* m_changeMask intentionally not copied */
|
|
m_primaryTableId = org.m_primaryTableId;
|
|
m_internalName.assign(org.m_internalName);
|
|
updateMysqlName();
|
|
// If the name has been explicitly set, use that name
|
|
// otherwise use the fetched name
|
|
if (!org.m_newExternalName.empty())
|
|
m_externalName.assign(org.m_newExternalName);
|
|
else
|
|
m_externalName.assign(org.m_externalName);
|
|
m_frm.assign(org.m_frm.get_data(), org.m_frm.length());
|
|
m_ts_name.assign(org.m_ts_name.get_data(), org.m_ts_name.length());
|
|
m_new_ts_name.assign(org.m_new_ts_name.get_data(),
|
|
org.m_new_ts_name.length());
|
|
m_ts.assign(org.m_ts.get_data(), org.m_ts.length());
|
|
m_new_ts.assign(org.m_new_ts.get_data(), org.m_new_ts.length());
|
|
m_fd.assign(org.m_fd.get_data(), org.m_fd.length());
|
|
m_new_fd.assign(org.m_new_fd.get_data(), org.m_new_fd.length());
|
|
m_range.assign(org.m_range.get_data(), org.m_range.length());
|
|
m_new_range.assign(org.m_new_range.get_data(), org.m_new_range.length());
|
|
|
|
m_fragmentType = org.m_fragmentType;
|
|
/*
|
|
m_columnHashMask, m_columnHash, m_hashValueMask, m_hashpointerValue
|
|
is state calculated by computeAggregates and buildColumnHash
|
|
*/
|
|
unsigned i;
|
|
for(i = 0; i < m_columns.size(); i++)
|
|
{
|
|
delete m_columns[i];
|
|
}
|
|
m_columns.clear();
|
|
for(i = 0; i < org.m_columns.size(); i++)
|
|
{
|
|
NdbColumnImpl * col = new NdbColumnImpl();
|
|
const NdbColumnImpl * iorg = org.m_columns[i];
|
|
(* col) = (* iorg);
|
|
m_columns.push_back(col);
|
|
}
|
|
|
|
m_fragments = org.m_fragments;
|
|
|
|
m_linear_flag = org.m_linear_flag;
|
|
m_max_rows = org.m_max_rows;
|
|
m_default_no_part_flag = org.m_default_no_part_flag;
|
|
m_logging = org.m_logging;
|
|
m_row_gci = org.m_row_gci;
|
|
m_row_checksum = org.m_row_checksum;
|
|
m_kvalue = org.m_kvalue;
|
|
m_minLoadFactor = org.m_minLoadFactor;
|
|
m_maxLoadFactor = org.m_maxLoadFactor;
|
|
m_keyLenInWords = org.m_keyLenInWords;
|
|
m_fragmentCount = org.m_fragmentCount;
|
|
|
|
if (m_index != 0)
|
|
delete m_index;
|
|
m_index = org.m_index;
|
|
|
|
m_primaryTable = org.m_primaryTable;
|
|
m_indexType = org.m_indexType;
|
|
|
|
m_noOfKeys = org.m_noOfKeys;
|
|
m_noOfDistributionKeys = org.m_noOfDistributionKeys;
|
|
m_noOfBlobs = org.m_noOfBlobs;
|
|
m_replicaCount = org.m_replicaCount;
|
|
|
|
m_id = org.m_id;
|
|
m_version = org.m_version;
|
|
m_status = org.m_status;
|
|
|
|
m_tablespace_name = org.m_tablespace_name;
|
|
m_tablespace_id= org.m_tablespace_id;
|
|
m_tablespace_version = org.m_tablespace_version;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void NdbTableImpl::setName(const char * name)
|
|
{
|
|
m_newExternalName.assign(name);
|
|
}
|
|
|
|
const char *
|
|
NdbTableImpl::getName() const
|
|
{
|
|
if (m_newExternalName.empty())
|
|
return m_externalName.c_str();
|
|
else
|
|
return m_newExternalName.c_str();
|
|
}
|
|
|
|
void
|
|
NdbTableImpl::computeAggregates()
|
|
{
|
|
m_noOfKeys = 0;
|
|
m_keyLenInWords = 0;
|
|
m_noOfDistributionKeys = 0;
|
|
m_noOfBlobs = 0;
|
|
Uint32 i, n;
|
|
for (i = 0; i < m_columns.size(); i++) {
|
|
NdbColumnImpl* col = m_columns[i];
|
|
if (col->m_pk) {
|
|
m_noOfKeys++;
|
|
m_keyLenInWords += (col->m_attrSize * col->m_arraySize + 3) / 4;
|
|
}
|
|
if (col->m_distributionKey == 2) // set by user
|
|
m_noOfDistributionKeys++;
|
|
|
|
if (col->getBlobType())
|
|
m_noOfBlobs++;
|
|
col->m_keyInfoPos = ~0;
|
|
}
|
|
if (m_noOfDistributionKeys == m_noOfKeys) {
|
|
// all is none!
|
|
m_noOfDistributionKeys = 0;
|
|
}
|
|
|
|
if (m_noOfDistributionKeys == 0)
|
|
{
|
|
// none is all!
|
|
for (i = 0, n = m_noOfKeys; n != 0; i++) {
|
|
NdbColumnImpl* col = m_columns[i];
|
|
if (col->m_pk) {
|
|
col->m_distributionKey = true; // set by us
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0, n = m_noOfKeys; n != 0; i++) {
|
|
NdbColumnImpl* col = m_columns[i];
|
|
if (col->m_pk)
|
|
{
|
|
if(col->m_distributionKey == 1)
|
|
col->m_distributionKey = 0;
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
|
|
Uint32 keyInfoPos = 0;
|
|
for (i = 0, n = m_noOfKeys; n != 0; i++) {
|
|
NdbColumnImpl* col = m_columns[i];
|
|
if (col->m_pk) {
|
|
col->m_keyInfoPos = keyInfoPos++;
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
|
|
const void*
|
|
NdbTableImpl::getTablespaceNames() const
|
|
{
|
|
if (m_new_ts_name.empty())
|
|
return m_ts_name.get_data();
|
|
else
|
|
return m_new_ts_name.get_data();
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::getTablespaceNamesLen() const
|
|
{
|
|
if (m_new_ts_name.empty())
|
|
return m_ts_name.length();
|
|
else
|
|
return m_new_ts_name.length();
|
|
}
|
|
|
|
void NdbTableImpl::setTablespaceNames(const void *data, Uint32 len)
|
|
{
|
|
m_new_ts_name.assign(data, len);
|
|
}
|
|
|
|
void NdbTableImpl::setFragmentCount(Uint32 count)
|
|
{
|
|
m_fragmentCount= count;
|
|
}
|
|
|
|
Uint32 NdbTableImpl::getFragmentCount() const
|
|
{
|
|
return m_fragmentCount;
|
|
}
|
|
|
|
void NdbTableImpl::setFrm(const void* data, Uint32 len)
|
|
{
|
|
m_newFrm.assign(data, len);
|
|
}
|
|
|
|
const void *
|
|
NdbTableImpl::getFrmData() const
|
|
{
|
|
if (m_newFrm.empty())
|
|
return m_frm.get_data();
|
|
else
|
|
return m_newFrm.get_data();
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::getFrmLength() const
|
|
{
|
|
if (m_newFrm.empty())
|
|
return m_frm.length();
|
|
else
|
|
return m_newFrm.length();
|
|
}
|
|
|
|
void NdbTableImpl::setFragmentData(const void* data, Uint32 len)
|
|
{
|
|
m_new_fd.assign(data, len);
|
|
}
|
|
|
|
const void *
|
|
NdbTableImpl::getFragmentData() const
|
|
{
|
|
if (m_new_fd.empty())
|
|
return m_fd.get_data();
|
|
else
|
|
return m_new_fd.get_data();
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::getFragmentDataLen() const
|
|
{
|
|
if (m_new_fd.empty())
|
|
return m_fd.length();
|
|
else
|
|
return m_new_fd.length();
|
|
}
|
|
|
|
void NdbTableImpl::setTablespaceData(const void* data, Uint32 len)
|
|
{
|
|
m_new_ts.assign(data, len);
|
|
}
|
|
|
|
const void *
|
|
NdbTableImpl::getTablespaceData() const
|
|
{
|
|
if (m_new_ts.empty())
|
|
return m_ts.get_data();
|
|
else
|
|
return m_new_ts.get_data();
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::getTablespaceDataLen() const
|
|
{
|
|
if (m_new_ts.empty())
|
|
return m_ts.length();
|
|
else
|
|
return m_new_ts.length();
|
|
}
|
|
|
|
void NdbTableImpl::setRangeListData(const void* data, Uint32 len)
|
|
{
|
|
m_new_range.assign(data, len);
|
|
}
|
|
|
|
const void *
|
|
NdbTableImpl::getRangeListData() const
|
|
{
|
|
if (m_new_range.empty())
|
|
return m_range.get_data();
|
|
else
|
|
return m_new_range.get_data();
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::getRangeListDataLen() const
|
|
{
|
|
if (m_new_range.empty())
|
|
return m_range.length();
|
|
else
|
|
return m_new_range.length();
|
|
}
|
|
|
|
void
|
|
NdbTableImpl::updateMysqlName()
|
|
{
|
|
Vector<BaseString> v;
|
|
if (m_internalName.split(v,"/") == 3)
|
|
{
|
|
m_mysqlName.assfmt("%s/%s",v[0].c_str(),v[2].c_str());
|
|
return;
|
|
}
|
|
m_mysqlName.assign("");
|
|
}
|
|
|
|
void
|
|
NdbTableImpl::buildColumnHash(){
|
|
const Uint32 size = m_columns.size();
|
|
int i;
|
|
for(i = 31; i >= 0; i--){
|
|
if(((1 << i) & size) != 0){
|
|
m_columnHashMask = (1 << (i + 1)) - 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Vector<Uint32> hashValues;
|
|
Vector<Vector<Uint32> > chains; chains.fill(size, hashValues);
|
|
for(i = 0; i< (int) size; i++){
|
|
Uint32 hv = Hash(m_columns[i]->getName()) & 0xFFFE;
|
|
Uint32 bucket = hv & m_columnHashMask;
|
|
bucket = (bucket < size ? bucket : bucket - size);
|
|
assert(bucket < size);
|
|
hashValues.push_back(hv);
|
|
chains[bucket].push_back(i);
|
|
}
|
|
|
|
m_columnHash.clear();
|
|
Uint32 tmp = 1;
|
|
m_columnHash.fill((unsigned)size-1, tmp); // Default no chaining
|
|
|
|
Uint32 pos = 0; // In overflow vector
|
|
for(i = 0; i< (int) size; i++){
|
|
Uint32 sz = chains[i].size();
|
|
if(sz == 1){
|
|
Uint32 col = chains[i][0];
|
|
Uint32 hv = hashValues[col];
|
|
Uint32 bucket = hv & m_columnHashMask;
|
|
bucket = (bucket < size ? bucket : bucket - size);
|
|
m_columnHash[bucket] = (col << 16) | hv | 1;
|
|
} else if(sz > 1){
|
|
Uint32 col = chains[i][0];
|
|
Uint32 hv = hashValues[col];
|
|
Uint32 bucket = hv & m_columnHashMask;
|
|
bucket = (bucket < size ? bucket : bucket - size);
|
|
m_columnHash[bucket] = (sz << 16) | (((size - bucket) + pos) << 1);
|
|
for(size_t j = 0; j<sz; j++, pos++){
|
|
Uint32 col = chains[i][j];
|
|
Uint32 hv = hashValues[col];
|
|
m_columnHash.push_back((col << 16) | hv);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_columnHash.push_back(0); // Overflow when looping in end of array
|
|
|
|
#if 0
|
|
for(size_t i = 0; i<m_columnHash.size(); i++){
|
|
Uint32 tmp = m_columnHash[i];
|
|
int col = -1;
|
|
if(i < size && (tmp & 1) == 1){
|
|
col = (tmp >> 16);
|
|
} else if(i >= size){
|
|
col = (tmp >> 16);
|
|
}
|
|
ndbout_c("m_columnHash[%d] %s = %x",
|
|
i, col > 0 ? m_columns[col]->getName() : "" , m_columnHash[i]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
Uint32
|
|
NdbTableImpl::get_nodes(Uint32 hashValue, const Uint16 ** nodes) const
|
|
{
|
|
Uint32 fragmentId;
|
|
if(m_replicaCount == 0)
|
|
return 0;
|
|
switch (m_fragmentType)
|
|
{
|
|
case NdbDictionary::Object::FragAllSmall:
|
|
case NdbDictionary::Object::FragAllMedium:
|
|
case NdbDictionary::Object::FragAllLarge:
|
|
case NdbDictionary::Object::FragSingle:
|
|
case NdbDictionary::Object::DistrKeyLin:
|
|
{
|
|
fragmentId = hashValue & m_hashValueMask;
|
|
if(fragmentId < m_hashpointerValue)
|
|
fragmentId = hashValue & ((m_hashValueMask << 1) + 1);
|
|
break;
|
|
}
|
|
case NdbDictionary::Object::DistrKeyHash:
|
|
{
|
|
fragmentId = hashValue % m_fragmentCount;
|
|
break;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
Uint32 pos = fragmentId * m_replicaCount;
|
|
if (pos + m_replicaCount <= m_fragments.size())
|
|
{
|
|
*nodes = m_fragments.getBase()+pos;
|
|
return m_replicaCount;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* NdbIndexImpl
|
|
*/
|
|
|
|
NdbIndexImpl::NdbIndexImpl() :
|
|
NdbDictionary::Index(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::OrderedIndex), m_facade(this)
|
|
{
|
|
init();
|
|
}
|
|
|
|
NdbIndexImpl::NdbIndexImpl(NdbDictionary::Index & f) :
|
|
NdbDictionary::Index(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::OrderedIndex), m_facade(&f)
|
|
{
|
|
init();
|
|
}
|
|
|
|
void NdbIndexImpl::init()
|
|
{
|
|
m_id= RNIL;
|
|
m_type= NdbDictionary::Object::TypeUndefined;
|
|
m_logging= true;
|
|
m_table= NULL;
|
|
}
|
|
|
|
NdbIndexImpl::~NdbIndexImpl(){
|
|
for (unsigned i = 0; i < m_columns.size(); i++)
|
|
delete m_columns[i];
|
|
}
|
|
|
|
void NdbIndexImpl::setName(const char * name)
|
|
{
|
|
m_externalName.assign(name);
|
|
}
|
|
|
|
const char *
|
|
NdbIndexImpl::getName() const
|
|
{
|
|
return m_externalName.c_str();
|
|
}
|
|
|
|
void
|
|
NdbIndexImpl::setTable(const char * table)
|
|
{
|
|
m_tableName.assign(table);
|
|
}
|
|
|
|
const char *
|
|
NdbIndexImpl::getTable() const
|
|
{
|
|
return m_tableName.c_str();
|
|
}
|
|
|
|
const NdbTableImpl *
|
|
NdbIndexImpl::getIndexTable() const
|
|
{
|
|
return m_table;
|
|
}
|
|
|
|
/**
|
|
* NdbEventImpl
|
|
*/
|
|
|
|
NdbEventImpl::NdbEventImpl() :
|
|
NdbDictionary::Event(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::TypeUndefined), m_facade(this)
|
|
{
|
|
DBUG_ENTER("NdbEventImpl::NdbEventImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
NdbEventImpl::NdbEventImpl(NdbDictionary::Event & f) :
|
|
NdbDictionary::Event(* this),
|
|
NdbDictObjectImpl(NdbDictionary::Object::TypeUndefined), m_facade(&f)
|
|
{
|
|
DBUG_ENTER("NdbEventImpl::NdbEventImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
init();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void NdbEventImpl::init()
|
|
{
|
|
m_eventId= RNIL;
|
|
m_eventKey= RNIL;
|
|
mi_type= 0;
|
|
m_dur= NdbDictionary::Event::ED_UNDEFINED;
|
|
m_mergeEvents = false;
|
|
m_tableImpl= NULL;
|
|
m_rep= NdbDictionary::Event::ER_UPDATED;
|
|
}
|
|
|
|
NdbEventImpl::~NdbEventImpl()
|
|
{
|
|
DBUG_ENTER("NdbEventImpl::~NdbEventImpl");
|
|
DBUG_PRINT("info", ("this: %p", this));
|
|
for (unsigned i = 0; i < m_columns.size(); i++)
|
|
delete m_columns[i];
|
|
if (m_tableImpl)
|
|
delete m_tableImpl;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void NdbEventImpl::setName(const char * name)
|
|
{
|
|
m_name.assign(name);
|
|
}
|
|
|
|
const char *NdbEventImpl::getName() const
|
|
{
|
|
return m_name.c_str();
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::setTable(const NdbDictionary::Table& table)
|
|
{
|
|
setTable(&NdbTableImpl::getImpl(table));
|
|
m_tableName.assign(m_tableImpl->getName());
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::setTable(NdbTableImpl *tableImpl)
|
|
{
|
|
DBUG_ENTER("NdbEventImpl::setTable");
|
|
DBUG_PRINT("info", ("this: %p tableImpl: %p", this, tableImpl));
|
|
DBUG_ASSERT(tableImpl->m_status != NdbDictionary::Object::Invalid);
|
|
if (!m_tableImpl)
|
|
m_tableImpl = new NdbTableImpl();
|
|
// Copy table, since event might be accessed from different threads
|
|
m_tableImpl->assign(*tableImpl);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
const NdbDictionary::Table *
|
|
NdbEventImpl::getTable() const
|
|
{
|
|
if (m_tableImpl)
|
|
return m_tableImpl->m_facade;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::setTable(const char * table)
|
|
{
|
|
m_tableName.assign(table);
|
|
}
|
|
|
|
const char *
|
|
NdbEventImpl::getTableName() const
|
|
{
|
|
return m_tableName.c_str();
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::addTableEvent(const NdbDictionary::Event::TableEvent t = NdbDictionary::Event::TE_ALL)
|
|
{
|
|
mi_type |= (unsigned)t;
|
|
}
|
|
|
|
bool
|
|
NdbEventImpl::getTableEvent(const NdbDictionary::Event::TableEvent t) const
|
|
{
|
|
return (mi_type & (unsigned)t) == (unsigned)t;
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::setDurability(NdbDictionary::Event::EventDurability d)
|
|
{
|
|
m_dur = d;
|
|
}
|
|
|
|
NdbDictionary::Event::EventDurability
|
|
NdbEventImpl::getDurability() const
|
|
{
|
|
return m_dur;
|
|
}
|
|
|
|
void
|
|
NdbEventImpl::setReport(NdbDictionary::Event::EventReport r)
|
|
{
|
|
m_rep = r;
|
|
}
|
|
|
|
NdbDictionary::Event::EventReport
|
|
NdbEventImpl::getReport() const
|
|
{
|
|
return m_rep;
|
|
}
|
|
|
|
int NdbEventImpl::getNoOfEventColumns() const
|
|
{
|
|
return m_attrIds.size() + m_columns.size();
|
|
}
|
|
|
|
const NdbDictionary::Column *
|
|
NdbEventImpl::getEventColumn(unsigned no) const
|
|
{
|
|
if (m_columns.size())
|
|
{
|
|
if (no < m_columns.size())
|
|
{
|
|
return m_columns[no];
|
|
}
|
|
}
|
|
else if (m_attrIds.size())
|
|
{
|
|
if (no < m_attrIds.size())
|
|
{
|
|
NdbTableImpl* tab= m_tableImpl;
|
|
if (tab == 0)
|
|
return 0;
|
|
return tab->getColumn(m_attrIds[no]);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* NdbDictionaryImpl
|
|
*/
|
|
|
|
NdbDictionaryImpl::NdbDictionaryImpl(Ndb &ndb)
|
|
: NdbDictionary::Dictionary(* this),
|
|
m_facade(this),
|
|
m_receiver(m_error),
|
|
m_ndb(ndb)
|
|
{
|
|
m_globalHash = 0;
|
|
m_local_table_data_size= 0;
|
|
}
|
|
|
|
NdbDictionaryImpl::NdbDictionaryImpl(Ndb &ndb,
|
|
NdbDictionary::Dictionary & f)
|
|
: NdbDictionary::Dictionary(* this),
|
|
m_facade(&f),
|
|
m_receiver(m_error),
|
|
m_ndb(ndb)
|
|
{
|
|
m_globalHash = 0;
|
|
m_local_table_data_size= 0;
|
|
}
|
|
|
|
static int f_dictionary_count = 0;
|
|
|
|
NdbDictionaryImpl::~NdbDictionaryImpl()
|
|
{
|
|
NdbElement_t<Ndb_local_table_info> * curr = m_localHash.m_tableHash.getNext(0);
|
|
if(m_globalHash){
|
|
while(curr != 0){
|
|
m_globalHash->lock();
|
|
m_globalHash->release(curr->theData->m_table_impl);
|
|
Ndb_local_table_info::destroy(curr->theData);
|
|
m_globalHash->unlock();
|
|
|
|
curr = m_localHash.m_tableHash.getNext(curr);
|
|
}
|
|
|
|
m_globalHash->lock();
|
|
if(--f_dictionary_count == 0){
|
|
delete NdbDictionary::Column::FRAGMENT;
|
|
delete NdbDictionary::Column::FRAGMENT_MEMORY;
|
|
delete NdbDictionary::Column::ROW_COUNT;
|
|
delete NdbDictionary::Column::COMMIT_COUNT;
|
|
delete NdbDictionary::Column::ROW_SIZE;
|
|
delete NdbDictionary::Column::RANGE_NO;
|
|
delete NdbDictionary::Column::DISK_REF;
|
|
delete NdbDictionary::Column::RECORDS_IN_RANGE;
|
|
delete NdbDictionary::Column::ROWID;
|
|
delete NdbDictionary::Column::ROW_GCI;
|
|
NdbDictionary::Column::FRAGMENT= 0;
|
|
NdbDictionary::Column::FRAGMENT_MEMORY= 0;
|
|
NdbDictionary::Column::ROW_COUNT= 0;
|
|
NdbDictionary::Column::COMMIT_COUNT= 0;
|
|
NdbDictionary::Column::ROW_SIZE= 0;
|
|
NdbDictionary::Column::RANGE_NO= 0;
|
|
NdbDictionary::Column::DISK_REF= 0;
|
|
NdbDictionary::Column::RECORDS_IN_RANGE= 0;
|
|
NdbDictionary::Column::ROWID= 0;
|
|
NdbDictionary::Column::ROW_GCI= 0;
|
|
}
|
|
m_globalHash->unlock();
|
|
} else {
|
|
assert(curr == 0);
|
|
}
|
|
}
|
|
|
|
NdbTableImpl *
|
|
NdbDictionaryImpl::fetchGlobalTableImplRef(const GlobalCacheInitObject &obj)
|
|
{
|
|
DBUG_ENTER("fetchGlobalTableImplRef");
|
|
NdbTableImpl *impl;
|
|
|
|
m_globalHash->lock();
|
|
impl = m_globalHash->get(obj.m_name.c_str());
|
|
m_globalHash->unlock();
|
|
|
|
if (impl == 0){
|
|
impl = m_receiver.getTable(obj.m_name.c_str(),
|
|
m_ndb.usingFullyQualifiedNames());
|
|
if (impl != 0 && obj.init(*impl))
|
|
{
|
|
delete impl;
|
|
impl = 0;
|
|
}
|
|
m_globalHash->lock();
|
|
m_globalHash->put(obj.m_name.c_str(), impl);
|
|
m_globalHash->unlock();
|
|
}
|
|
|
|
DBUG_RETURN(impl);
|
|
}
|
|
|
|
void
|
|
NdbDictionaryImpl::putTable(NdbTableImpl *impl)
|
|
{
|
|
NdbTableImpl *old;
|
|
|
|
int ret = getBlobTables(*impl);
|
|
assert(ret == 0);
|
|
|
|
m_globalHash->lock();
|
|
if ((old= m_globalHash->get(impl->m_internalName.c_str())))
|
|
{
|
|
m_globalHash->alter_table_rep(old->m_internalName.c_str(),
|
|
impl->m_id,
|
|
impl->m_version,
|
|
FALSE);
|
|
}
|
|
m_globalHash->put(impl->m_internalName.c_str(), impl);
|
|
m_globalHash->unlock();
|
|
Ndb_local_table_info *info=
|
|
Ndb_local_table_info::create(impl, m_local_table_data_size);
|
|
|
|
m_localHash.put(impl->m_internalName.c_str(), info);
|
|
|
|
m_ndb.theFirstTupleId[impl->getTableId()] = ~0;
|
|
m_ndb.theLastTupleId[impl->getTableId()] = ~0;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::getBlobTables(NdbTableImpl &t)
|
|
{
|
|
unsigned n= t.m_noOfBlobs;
|
|
DBUG_ENTER("NdbDictionaryImpl::addBlobTables");
|
|
// optimized for blob column being the last one
|
|
// and not looking for more than one if not neccessary
|
|
for (unsigned i = t.m_columns.size(); i > 0 && n > 0;) {
|
|
i--;
|
|
NdbColumnImpl & c = *t.m_columns[i];
|
|
if (! c.getBlobType() || c.getPartSize() == 0)
|
|
continue;
|
|
n--;
|
|
// retrieve blob table def from DICT - by-pass cache
|
|
char btname[NdbBlobImpl::BlobTableNameSize];
|
|
NdbBlob::getBlobTableName(btname, &t, &c);
|
|
BaseString btname_internal = m_ndb.internalize_table_name(btname);
|
|
NdbTableImpl* bt =
|
|
m_receiver.getTable(btname_internal, m_ndb.usingFullyQualifiedNames());
|
|
if (bt == NULL)
|
|
DBUG_RETURN(-1);
|
|
|
|
// TODO check primary id/version when returned by DICT
|
|
|
|
// the blob column owns the blob table
|
|
assert(c.m_blobTable == NULL);
|
|
c.m_blobTable = bt;
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
NdbTableImpl*
|
|
NdbDictionaryImpl::getBlobTable(const NdbTableImpl& tab, uint col_no)
|
|
{
|
|
if (col_no < tab.m_columns.size()) {
|
|
NdbColumnImpl* col = tab.m_columns[col_no];
|
|
if (col != NULL) {
|
|
NdbTableImpl* bt = col->m_blobTable;
|
|
if (bt != NULL)
|
|
return bt;
|
|
else
|
|
m_error.code = 4273; // No blob table..
|
|
} else
|
|
m_error.code = 4249; // Invalid table..
|
|
} else
|
|
m_error.code = 4318; // Invalid attribute..
|
|
return NULL;
|
|
}
|
|
|
|
NdbTableImpl*
|
|
NdbDictionaryImpl::getBlobTable(uint tab_id, uint col_no)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::getBlobTable");
|
|
DBUG_PRINT("enter", ("tab_id: %u col_no %u", tab_id, col_no));
|
|
|
|
NdbTableImpl* tab = m_receiver.getTable(tab_id,
|
|
m_ndb.usingFullyQualifiedNames());
|
|
if (tab == NULL)
|
|
DBUG_RETURN(NULL);
|
|
Ndb_local_table_info* info =
|
|
get_local_table_info(tab->m_internalName);
|
|
delete tab;
|
|
if (info == NULL)
|
|
DBUG_RETURN(NULL);
|
|
NdbTableImpl* bt = getBlobTable(*info->m_table_impl, col_no);
|
|
DBUG_RETURN(bt);
|
|
}
|
|
|
|
#if 0
|
|
bool
|
|
NdbDictionaryImpl::setTransporter(class TransporterFacade * tf)
|
|
{
|
|
if(tf != 0){
|
|
m_globalHash = &tf->m_globalDictCache;
|
|
return m_receiver.setTransporter(tf);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
bool
|
|
NdbDictionaryImpl::setTransporter(class Ndb* ndb,
|
|
class TransporterFacade * tf)
|
|
{
|
|
m_globalHash = &tf->m_globalDictCache;
|
|
if(m_receiver.setTransporter(ndb, tf)){
|
|
m_globalHash->lock();
|
|
if(f_dictionary_count++ == 0){
|
|
NdbDictionary::Column::FRAGMENT=
|
|
NdbColumnImpl::create_pseudo("NDB$FRAGMENT");
|
|
NdbDictionary::Column::FRAGMENT_MEMORY=
|
|
NdbColumnImpl::create_pseudo("NDB$FRAGMENT_MEMORY");
|
|
NdbDictionary::Column::ROW_COUNT=
|
|
NdbColumnImpl::create_pseudo("NDB$ROW_COUNT");
|
|
NdbDictionary::Column::COMMIT_COUNT=
|
|
NdbColumnImpl::create_pseudo("NDB$COMMIT_COUNT");
|
|
NdbDictionary::Column::ROW_SIZE=
|
|
NdbColumnImpl::create_pseudo("NDB$ROW_SIZE");
|
|
NdbDictionary::Column::RANGE_NO=
|
|
NdbColumnImpl::create_pseudo("NDB$RANGE_NO");
|
|
NdbDictionary::Column::DISK_REF=
|
|
NdbColumnImpl::create_pseudo("NDB$DISK_REF");
|
|
NdbDictionary::Column::RECORDS_IN_RANGE=
|
|
NdbColumnImpl::create_pseudo("NDB$RECORDS_IN_RANGE");
|
|
NdbDictionary::Column::ROWID=
|
|
NdbColumnImpl::create_pseudo("NDB$ROWID");
|
|
NdbDictionary::Column::ROW_GCI=
|
|
NdbColumnImpl::create_pseudo("NDB$ROW_GCI");
|
|
}
|
|
m_globalHash->unlock();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
NdbTableImpl *
|
|
NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index,
|
|
NdbTableImpl * table)
|
|
{
|
|
const BaseString internalName(
|
|
m_ndb.internalize_index_name(table, index->getName()));
|
|
return getTable(m_ndb.externalizeTableName(internalName.c_str()));
|
|
}
|
|
|
|
#if 0
|
|
bool
|
|
NdbDictInterface::setTransporter(class TransporterFacade * tf)
|
|
{
|
|
if(tf == 0)
|
|
return false;
|
|
|
|
Guard g(tf->theMutexPtr);
|
|
|
|
m_blockNumber = tf->open(this,
|
|
execSignal,
|
|
execNodeStatus);
|
|
|
|
if ( m_blockNumber == -1 ) {
|
|
m_error.code= 4105;
|
|
return false; // no more free blocknumbers
|
|
}//if
|
|
Uint32 theNode = tf->ownId();
|
|
m_reference = numberToRef(m_blockNumber, theNode);
|
|
m_transporter = tf;
|
|
m_waiter.m_mutex = tf->theMutexPtr;
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
bool
|
|
NdbDictInterface::setTransporter(class Ndb* ndb, class TransporterFacade * tf)
|
|
{
|
|
m_reference = ndb->getReference();
|
|
m_transporter = tf;
|
|
m_waiter.m_mutex = tf->theMutexPtr;
|
|
|
|
return true;
|
|
}
|
|
|
|
NdbDictInterface::~NdbDictInterface()
|
|
{
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execSignal(void* dictImpl,
|
|
class NdbApiSignal* signal,
|
|
class LinearSectionPtr ptr[3])
|
|
{
|
|
NdbDictInterface * tmp = (NdbDictInterface*)dictImpl;
|
|
|
|
const Uint32 gsn = signal->readSignalNumber();
|
|
switch(gsn){
|
|
case GSN_GET_TABINFOREF:
|
|
tmp->execGET_TABINFO_REF(signal, ptr);
|
|
break;
|
|
case GSN_GET_TABINFO_CONF:
|
|
tmp->execGET_TABINFO_CONF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_TABLE_REF:
|
|
tmp->execCREATE_TABLE_REF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_TABLE_CONF:
|
|
tmp->execCREATE_TABLE_CONF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_TABLE_REF:
|
|
tmp->execDROP_TABLE_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_TABLE_CONF:
|
|
tmp->execDROP_TABLE_CONF(signal, ptr);
|
|
break;
|
|
case GSN_ALTER_TABLE_REF:
|
|
tmp->execALTER_TABLE_REF(signal, ptr);
|
|
break;
|
|
case GSN_ALTER_TABLE_CONF:
|
|
tmp->execALTER_TABLE_CONF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_INDX_REF:
|
|
tmp->execCREATE_INDX_REF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_INDX_CONF:
|
|
tmp->execCREATE_INDX_CONF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_INDX_REF:
|
|
tmp->execDROP_INDX_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_INDX_CONF:
|
|
tmp->execDROP_INDX_CONF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_EVNT_REF:
|
|
tmp->execCREATE_EVNT_REF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_EVNT_CONF:
|
|
tmp->execCREATE_EVNT_CONF(signal, ptr);
|
|
break;
|
|
case GSN_SUB_START_CONF:
|
|
tmp->execSUB_START_CONF(signal, ptr);
|
|
break;
|
|
case GSN_SUB_START_REF:
|
|
tmp->execSUB_START_REF(signal, ptr);
|
|
break;
|
|
case GSN_SUB_STOP_CONF:
|
|
tmp->execSUB_STOP_CONF(signal, ptr);
|
|
break;
|
|
case GSN_SUB_STOP_REF:
|
|
tmp->execSUB_STOP_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_EVNT_REF:
|
|
tmp->execDROP_EVNT_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_EVNT_CONF:
|
|
tmp->execDROP_EVNT_CONF(signal, ptr);
|
|
break;
|
|
case GSN_LIST_TABLES_CONF:
|
|
tmp->execLIST_TABLES_CONF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_FILEGROUP_REF:
|
|
tmp->execCREATE_FILEGROUP_REF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_FILEGROUP_CONF:
|
|
tmp->execCREATE_FILEGROUP_CONF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_FILE_REF:
|
|
tmp->execCREATE_FILE_REF(signal, ptr);
|
|
break;
|
|
case GSN_CREATE_FILE_CONF:
|
|
tmp->execCREATE_FILE_CONF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_FILEGROUP_REF:
|
|
tmp->execDROP_FILEGROUP_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_FILEGROUP_CONF:
|
|
tmp->execDROP_FILEGROUP_CONF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_FILE_REF:
|
|
tmp->execDROP_FILE_REF(signal, ptr);
|
|
break;
|
|
case GSN_DROP_FILE_CONF:
|
|
tmp->execDROP_FILE_CONF(signal, ptr);
|
|
break;
|
|
case GSN_WAIT_GCP_CONF:
|
|
tmp->execWAIT_GCP_CONF(signal, ptr);
|
|
break;
|
|
case GSN_WAIT_GCP_REF:
|
|
tmp->execWAIT_GCP_REF(signal, ptr);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execNodeStatus(void* dictImpl, Uint32 aNode,
|
|
bool alive, bool nfCompleted)
|
|
{
|
|
NdbDictInterface * tmp = (NdbDictInterface*)dictImpl;
|
|
|
|
if(!alive && !nfCompleted){
|
|
return;
|
|
}
|
|
|
|
if (!alive && nfCompleted){
|
|
tmp->m_waiter.nodeFail(aNode);
|
|
}
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::dictSignal(NdbApiSignal* sig,
|
|
LinearSectionPtr ptr[3], int secs,
|
|
int node_specification,
|
|
WaitSignalType wst,
|
|
int timeout, Uint32 RETRIES,
|
|
const int *errcodes, int temporaryMask)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::dictSignal");
|
|
DBUG_PRINT("enter", ("useMasterNodeId: %d", node_specification));
|
|
for(Uint32 i = 0; i<RETRIES; i++){
|
|
m_buffer.clear();
|
|
|
|
// Protected area
|
|
/*
|
|
The PollGuard has an implicit call of unlock_and_signal through the
|
|
~PollGuard method. This method is called implicitly by the compiler
|
|
in all places where the object is out of context due to a return,
|
|
break, continue or simply end of statement block
|
|
*/
|
|
PollGuard poll_guard(m_transporter, &m_waiter, refToBlock(m_reference));
|
|
Uint32 node;
|
|
switch(node_specification){
|
|
case 0:
|
|
node = (m_transporter->get_node_alive(m_masterNodeId) ? m_masterNodeId :
|
|
(m_masterNodeId = m_transporter->get_an_alive_node()));
|
|
break;
|
|
case -1:
|
|
node = m_transporter->get_an_alive_node();
|
|
break;
|
|
default:
|
|
node = node_specification;
|
|
}
|
|
DBUG_PRINT("info", ("node %d", node));
|
|
if(node == 0){
|
|
m_error.code= 4009;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
int res = (ptr ?
|
|
m_transporter->sendFragmentedSignal(sig, node, ptr, secs):
|
|
m_transporter->sendSignal(sig, node));
|
|
if(res != 0){
|
|
DBUG_PRINT("info", ("dictSignal failed to send signal"));
|
|
continue;
|
|
}
|
|
|
|
m_error.code= 0;
|
|
int ret_val= poll_guard.wait_n_unlock(timeout, node, wst);
|
|
// End of Protected area
|
|
|
|
if(ret_val == 0 && m_error.code == 0){
|
|
// Normal return
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/**
|
|
* Handle error codes
|
|
*/
|
|
if(ret_val == -2) //WAIT_NODE_FAILURE
|
|
{
|
|
continue;
|
|
}
|
|
if(m_waiter.m_state == WST_WAIT_TIMEOUT)
|
|
{
|
|
DBUG_PRINT("info", ("dictSignal caught time-out"));
|
|
m_error.code = 4008;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
if ( temporaryMask == -1)
|
|
{
|
|
const NdbError &error= getNdbError();
|
|
if (error.status == NdbError::TemporaryError)
|
|
continue;
|
|
}
|
|
else if ( (temporaryMask & m_error.code) != 0 ) {
|
|
continue;
|
|
}
|
|
DBUG_PRINT("info", ("dictSignal caught error= %d", m_error.code));
|
|
|
|
if(m_error.code && errcodes)
|
|
{
|
|
int j;
|
|
for(j = 0; errcodes[j] ; j++){
|
|
if(m_error.code == errcodes[j]){
|
|
break;
|
|
}
|
|
}
|
|
if(errcodes[j]) // Accepted error code
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
/*
|
|
Get dictionary information for a table using table id as reference
|
|
|
|
DESCRIPTION
|
|
Sends a GET_TABINFOREQ signal containing the table id
|
|
*/
|
|
NdbTableImpl *
|
|
NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames)
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
|
|
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestType =
|
|
GetTabInfoReq::RequestById | GetTabInfoReq::LongSignalConf;
|
|
req->tableId = tableId;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_GET_TABINFOREQ;
|
|
tSignal.theLength = GetTabInfoReq::SignalLength;
|
|
|
|
return getTable(&tSignal, 0, 0, fullyQualifiedNames);
|
|
}
|
|
|
|
/*
|
|
Get dictionary information for a table using table name as the reference
|
|
|
|
DESCRIPTION
|
|
Send GET_TABINFOREQ signal with the table name in the first
|
|
long section part
|
|
*/
|
|
|
|
NdbTableImpl *
|
|
NdbDictInterface::getTable(const BaseString& name, bool fullyQualifiedNames)
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
GetTabInfoReq* const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
|
|
|
|
const Uint32 namelen= name.length() + 1; // NULL terminated
|
|
const Uint32 namelen_words= (namelen + 3) >> 2; // Size in words
|
|
|
|
req->senderRef= m_reference;
|
|
req->senderData= 0;
|
|
req->requestType=
|
|
GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
|
|
req->tableNameLen= namelen;
|
|
tSignal.theReceiversBlockNumber= DBDICT;
|
|
tSignal.theVerId_signalNumber= GSN_GET_TABINFOREQ;
|
|
tSignal.theLength= GetTabInfoReq::SignalLength;
|
|
|
|
// Copy name to m_buffer to get a word sized buffer
|
|
m_buffer.clear();
|
|
m_buffer.grow(namelen_words*4+4);
|
|
m_buffer.append(name.c_str(), namelen);
|
|
|
|
#ifndef IGNORE_VALGRIND_WARNINGS
|
|
Uint32 pad = 0;
|
|
m_buffer.append(&pad, 4);
|
|
#endif
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p= (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz= namelen_words;
|
|
|
|
return getTable(&tSignal, ptr, 1, fullyQualifiedNames);
|
|
}
|
|
|
|
|
|
NdbTableImpl *
|
|
NdbDictInterface::getTable(class NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3],
|
|
Uint32 noOfSections, bool fullyQualifiedNames)
|
|
{
|
|
int errCodes[] = {GetTabInfoRef::Busy, 0 };
|
|
int r = dictSignal(signal, ptr, noOfSections,
|
|
-1, // any node
|
|
WAIT_GET_TAB_INFO_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100, errCodes);
|
|
|
|
if (r)
|
|
return 0;
|
|
|
|
NdbTableImpl * rt = 0;
|
|
m_error.code = parseTableInfo(&rt,
|
|
(Uint32*)m_buffer.get_data(),
|
|
m_buffer.length() / 4,
|
|
fullyQualifiedNames);
|
|
if(rt)
|
|
rt->buildColumnHash();
|
|
|
|
return rt;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execGET_TABINFO_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const GetTabInfoConf* conf = CAST_CONSTPTR(GetTabInfoConf, signal->getDataPtr());
|
|
if(signal->isFirstFragment()){
|
|
m_fragmentId = signal->getFragmentId();
|
|
m_buffer.grow(4 * conf->totalLen);
|
|
} else {
|
|
if(m_fragmentId != signal->getFragmentId()){
|
|
abort();
|
|
}
|
|
}
|
|
|
|
const Uint32 i = GetTabInfoConf::DICT_TAB_INFO;
|
|
m_buffer.append(ptr[i].p, 4 * ptr[i].sz);
|
|
|
|
if(!signal->isLastFragment()){
|
|
return;
|
|
}
|
|
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execGET_TABINFO_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const GetTabInfoRef* ref = CAST_CONSTPTR(GetTabInfoRef,
|
|
signal->getDataPtr());
|
|
|
|
m_error.code= ref->errorCode;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Pack/Unpack tables
|
|
*/
|
|
struct ApiKernelMapping {
|
|
Int32 kernelConstant;
|
|
Int32 apiConstant;
|
|
};
|
|
|
|
Uint32
|
|
getApiConstant(Int32 kernelConstant, const ApiKernelMapping map[], Uint32 def)
|
|
{
|
|
int i = 0;
|
|
while(map[i].kernelConstant != kernelConstant){
|
|
if(map[i].kernelConstant == -1 &&
|
|
map[i].apiConstant == -1){
|
|
return def;
|
|
}
|
|
i++;
|
|
}
|
|
return map[i].apiConstant;
|
|
}
|
|
|
|
Uint32
|
|
getKernelConstant(Int32 apiConstant, const ApiKernelMapping map[], Uint32 def)
|
|
{
|
|
int i = 0;
|
|
while(map[i].apiConstant != apiConstant){
|
|
if(map[i].kernelConstant == -1 &&
|
|
map[i].apiConstant == -1){
|
|
return def;
|
|
}
|
|
i++;
|
|
}
|
|
return map[i].kernelConstant;
|
|
}
|
|
|
|
static const
|
|
ApiKernelMapping
|
|
fragmentTypeMapping[] = {
|
|
{ DictTabInfo::AllNodesSmallTable, NdbDictionary::Object::FragAllSmall },
|
|
{ DictTabInfo::AllNodesMediumTable, NdbDictionary::Object::FragAllMedium },
|
|
{ DictTabInfo::AllNodesLargeTable, NdbDictionary::Object::FragAllLarge },
|
|
{ DictTabInfo::SingleFragment, NdbDictionary::Object::FragSingle },
|
|
{ DictTabInfo::DistrKeyHash, NdbDictionary::Object::DistrKeyHash },
|
|
{ DictTabInfo::DistrKeyLin, NdbDictionary::Object::DistrKeyLin },
|
|
{ DictTabInfo::UserDefined, NdbDictionary::Object::UserDefined },
|
|
{ -1, -1 }
|
|
};
|
|
|
|
static const
|
|
ApiKernelMapping
|
|
objectTypeMapping[] = {
|
|
{ DictTabInfo::SystemTable, NdbDictionary::Object::SystemTable },
|
|
{ DictTabInfo::UserTable, NdbDictionary::Object::UserTable },
|
|
{ DictTabInfo::UniqueHashIndex, NdbDictionary::Object::UniqueHashIndex },
|
|
{ DictTabInfo::OrderedIndex, NdbDictionary::Object::OrderedIndex },
|
|
{ DictTabInfo::HashIndexTrigger, NdbDictionary::Object::HashIndexTrigger },
|
|
{ DictTabInfo::IndexTrigger, NdbDictionary::Object::IndexTrigger },
|
|
{ DictTabInfo::SubscriptionTrigger,NdbDictionary::Object::SubscriptionTrigger },
|
|
{ DictTabInfo::ReadOnlyConstraint ,NdbDictionary::Object::ReadOnlyConstraint },
|
|
{ DictTabInfo::Tablespace, NdbDictionary::Object::Tablespace },
|
|
{ DictTabInfo::LogfileGroup, NdbDictionary::Object::LogfileGroup },
|
|
{ DictTabInfo::Datafile, NdbDictionary::Object::Datafile },
|
|
{ DictTabInfo::Undofile, NdbDictionary::Object::Undofile },
|
|
{ -1, -1 }
|
|
};
|
|
|
|
static const
|
|
ApiKernelMapping
|
|
objectStateMapping[] = {
|
|
{ DictTabInfo::StateOffline, NdbDictionary::Object::StateOffline },
|
|
{ DictTabInfo::StateBuilding, NdbDictionary::Object::StateBuilding },
|
|
{ DictTabInfo::StateDropping, NdbDictionary::Object::StateDropping },
|
|
{ DictTabInfo::StateOnline, NdbDictionary::Object::StateOnline },
|
|
{ DictTabInfo::StateBackup, NdbDictionary::Object::StateBackup },
|
|
{ DictTabInfo::StateBroken, NdbDictionary::Object::StateBroken },
|
|
{ -1, -1 }
|
|
};
|
|
|
|
static const
|
|
ApiKernelMapping
|
|
objectStoreMapping[] = {
|
|
{ DictTabInfo::StoreTemporary, NdbDictionary::Object::StoreTemporary },
|
|
{ DictTabInfo::StorePermanent, NdbDictionary::Object::StorePermanent },
|
|
{ -1, -1 }
|
|
};
|
|
|
|
static const
|
|
ApiKernelMapping
|
|
indexTypeMapping[] = {
|
|
{ DictTabInfo::UniqueHashIndex, NdbDictionary::Index::UniqueHashIndex },
|
|
{ DictTabInfo::OrderedIndex, NdbDictionary::Index::OrderedIndex },
|
|
{ -1, -1 }
|
|
};
|
|
|
|
int
|
|
NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
|
|
const Uint32 * data, Uint32 len,
|
|
bool fullyQualifiedNames,
|
|
Uint32 version)
|
|
{
|
|
SimplePropertiesLinearReader it(data, len);
|
|
DictTabInfo::Table *tableDesc;
|
|
SimpleProperties::UnpackStatus s;
|
|
DBUG_ENTER("NdbDictInterface::parseTableInfo");
|
|
|
|
tableDesc = (DictTabInfo::Table*)NdbMem_Allocate(sizeof(DictTabInfo::Table));
|
|
if (!tableDesc)
|
|
{
|
|
DBUG_RETURN(4000);
|
|
}
|
|
tableDesc->init();
|
|
s = SimpleProperties::unpack(it, tableDesc,
|
|
DictTabInfo::TableMapping,
|
|
DictTabInfo::TableMappingSize,
|
|
true, true);
|
|
|
|
if(s != SimpleProperties::Break){
|
|
NdbMem_Free((void*)tableDesc);
|
|
DBUG_RETURN(703);
|
|
}
|
|
const char * internalName = tableDesc->TableName;
|
|
const char * externalName = Ndb::externalizeTableName(internalName, fullyQualifiedNames);
|
|
|
|
NdbTableImpl * impl = new NdbTableImpl();
|
|
impl->m_id = tableDesc->TableId;
|
|
impl->m_version = tableDesc->TableVersion;
|
|
impl->m_status = NdbDictionary::Object::Retrieved;
|
|
impl->m_internalName.assign(internalName);
|
|
impl->updateMysqlName();
|
|
impl->m_externalName.assign(externalName);
|
|
|
|
impl->m_frm.assign(tableDesc->FrmData, tableDesc->FrmLen);
|
|
impl->m_fd.assign(tableDesc->FragmentData, tableDesc->FragmentDataLen);
|
|
impl->m_range.assign(tableDesc->RangeListData, tableDesc->RangeListDataLen);
|
|
impl->m_fragmentCount = tableDesc->FragmentCount;
|
|
|
|
/*
|
|
We specifically don't get tablespace data and range/list arrays here
|
|
since those are known by the MySQL Server through analysing the
|
|
frm file.
|
|
Fragment Data contains the real node group mapping and the fragment
|
|
identities used for each fragment. At the moment we have no need for
|
|
this.
|
|
Frm file is needed for autodiscovery.
|
|
*/
|
|
|
|
impl->m_fragmentType = (NdbDictionary::Object::FragmentType)
|
|
getApiConstant(tableDesc->FragmentType,
|
|
fragmentTypeMapping,
|
|
(Uint32)NdbDictionary::Object::FragUndefined);
|
|
|
|
Uint64 max_rows = ((Uint64)tableDesc->MaxRowsHigh) << 32;
|
|
max_rows += tableDesc->MaxRowsLow;
|
|
impl->m_max_rows = max_rows;
|
|
impl->m_default_no_part_flag = tableDesc->DefaultNoPartFlag;
|
|
impl->m_linear_flag = tableDesc->LinearHashFlag;
|
|
impl->m_logging = tableDesc->TableLoggedFlag;
|
|
impl->m_row_gci = tableDesc->RowGCIFlag;
|
|
impl->m_row_checksum = tableDesc->RowChecksumFlag;
|
|
impl->m_kvalue = tableDesc->TableKValue;
|
|
impl->m_minLoadFactor = tableDesc->MinLoadFactor;
|
|
impl->m_maxLoadFactor = tableDesc->MaxLoadFactor;
|
|
|
|
impl->m_indexType = (NdbDictionary::Object::Type)
|
|
getApiConstant(tableDesc->TableType,
|
|
indexTypeMapping,
|
|
NdbDictionary::Object::TypeUndefined);
|
|
|
|
if(impl->m_indexType == NdbDictionary::Object::TypeUndefined){
|
|
} else {
|
|
const char * externalPrimary =
|
|
Ndb::externalizeTableName(tableDesc->PrimaryTable, fullyQualifiedNames);
|
|
impl->m_primaryTable.assign(externalPrimary);
|
|
}
|
|
|
|
Uint32 i;
|
|
for(i = 0; i < tableDesc->NoOfAttributes; i++) {
|
|
DictTabInfo::Attribute attrDesc; attrDesc.init();
|
|
s = SimpleProperties::unpack(it,
|
|
&attrDesc,
|
|
DictTabInfo::AttributeMapping,
|
|
DictTabInfo::AttributeMappingSize,
|
|
true, true);
|
|
if(s != SimpleProperties::Break){
|
|
delete impl;
|
|
NdbMem_Free((void*)tableDesc);
|
|
DBUG_RETURN(703);
|
|
}
|
|
|
|
NdbColumnImpl * col = new NdbColumnImpl();
|
|
col->m_attrId = attrDesc.AttributeId;
|
|
col->setName(attrDesc.AttributeName);
|
|
|
|
// check type and compute attribute size and array size
|
|
if (! attrDesc.translateExtType()) {
|
|
delete impl;
|
|
NdbMem_Free((void*)tableDesc);
|
|
DBUG_RETURN(703);
|
|
}
|
|
col->m_type = (NdbDictionary::Column::Type)attrDesc.AttributeExtType;
|
|
col->m_precision = (attrDesc.AttributeExtPrecision & 0xFFFF);
|
|
col->m_scale = attrDesc.AttributeExtScale;
|
|
col->m_length = attrDesc.AttributeExtLength;
|
|
// charset in upper half of precision
|
|
unsigned cs_number = (attrDesc.AttributeExtPrecision >> 16);
|
|
// charset is defined exactly for char types
|
|
if (col->getCharType() != (cs_number != 0)) {
|
|
delete impl;
|
|
NdbMem_Free((void*)tableDesc);
|
|
DBUG_RETURN(703);
|
|
}
|
|
if (col->getCharType()) {
|
|
col->m_cs = get_charset(cs_number, MYF(0));
|
|
if (col->m_cs == NULL) {
|
|
delete impl;
|
|
NdbMem_Free((void*)tableDesc);
|
|
DBUG_RETURN(743);
|
|
}
|
|
}
|
|
col->m_attrSize = (1 << attrDesc.AttributeSize) / 8;
|
|
col->m_arraySize = attrDesc.AttributeArraySize;
|
|
col->m_arrayType = attrDesc.AttributeArrayType;
|
|
if(attrDesc.AttributeSize == 0)
|
|
{
|
|
col->m_attrSize = 4;
|
|
col->m_arraySize = (attrDesc.AttributeArraySize + 31) >> 5;
|
|
}
|
|
col->m_storageType = attrDesc.AttributeStorageType;
|
|
|
|
col->m_pk = attrDesc.AttributeKeyFlag;
|
|
col->m_distributionKey = attrDesc.AttributeDKey ? 2 : 0;
|
|
col->m_nullable = attrDesc.AttributeNullableFlag;
|
|
col->m_autoIncrement = (attrDesc.AttributeAutoIncrement ? true : false);
|
|
col->m_autoIncrementInitialValue = ~0;
|
|
col->m_defaultValue.assign(attrDesc.AttributeDefaultValue);
|
|
|
|
col->m_column_no = impl->m_columns.size();
|
|
impl->m_columns.push_back(col);
|
|
it.next();
|
|
}
|
|
|
|
impl->computeAggregates();
|
|
|
|
if(tableDesc->ReplicaDataLen > 0)
|
|
{
|
|
Uint16 replicaCount = ntohs(tableDesc->ReplicaData[0]);
|
|
Uint16 fragCount = ntohs(tableDesc->ReplicaData[1]);
|
|
|
|
impl->m_replicaCount = replicaCount;
|
|
impl->m_fragmentCount = fragCount;
|
|
DBUG_PRINT("info", ("replicaCount=%x , fragCount=%x",replicaCount,fragCount));
|
|
for(i = 0; i < (Uint32) (fragCount*replicaCount); i++)
|
|
{
|
|
impl->m_fragments.push_back(ntohs(tableDesc->ReplicaData[i+2]));
|
|
}
|
|
|
|
Uint32 topBit = (1 << 31);
|
|
for(; topBit && !(fragCount & topBit); ){
|
|
topBit >>= 1;
|
|
}
|
|
impl->m_hashValueMask = topBit - 1;
|
|
impl->m_hashpointerValue = fragCount - (impl->m_hashValueMask + 1);
|
|
}
|
|
else
|
|
{
|
|
impl->m_fragmentCount = tableDesc->FragmentCount;
|
|
impl->m_replicaCount = 0;
|
|
impl->m_hashValueMask = 0;
|
|
impl->m_hashpointerValue = 0;
|
|
}
|
|
|
|
impl->m_tablespace_id = tableDesc->TablespaceId;
|
|
impl->m_tablespace_version = tableDesc->TablespaceVersion;
|
|
|
|
* ret = impl;
|
|
|
|
NdbMem_Free((void*)tableDesc);
|
|
if (version < MAKE_VERSION(5,1,3))
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
DBUG_ASSERT(impl->m_fragmentCount > 0);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Create table and alter table
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::createTable(NdbTableImpl &t)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::createTable");
|
|
|
|
// if the new name has not been set, use the copied name
|
|
if (t.m_newExternalName.empty())
|
|
t.m_newExternalName.assign(t.m_externalName);
|
|
|
|
// create table
|
|
if (m_receiver.createTable(m_ndb, t) != 0)
|
|
DBUG_RETURN(-1);
|
|
Uint32* data = (Uint32*)m_receiver.m_buffer.get_data();
|
|
t.m_id = data[0];
|
|
t.m_version = data[1];
|
|
|
|
// update table def from DICT - by-pass cache
|
|
NdbTableImpl* t2 =
|
|
m_receiver.getTable(t.m_internalName, m_ndb.usingFullyQualifiedNames());
|
|
|
|
// check if we got back same table
|
|
if (t2 == NULL) {
|
|
DBUG_PRINT("info", ("table %s dropped by another thread",
|
|
t.m_internalName.c_str()));
|
|
m_error.code = 283;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
if (t.m_id != t2->m_id || t.m_version != t2->m_version) {
|
|
DBUG_PRINT("info", ("table %s re-created by another thread",
|
|
t.m_internalName.c_str()));
|
|
m_error.code = 283;
|
|
delete t2;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
// auto-increment - use "t" because initial value is not in DICT
|
|
{
|
|
bool autoIncrement = false;
|
|
Uint64 initialValue = 0;
|
|
for (Uint32 i = 0; i < t.m_columns.size(); i++) {
|
|
const NdbColumnImpl* c = t.m_columns[i];
|
|
assert(c != NULL);
|
|
if (c->m_autoIncrement) {
|
|
if (autoIncrement) {
|
|
m_error.code = 4335;
|
|
delete t2;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
autoIncrement = true;
|
|
initialValue = c->m_autoIncrementInitialValue;
|
|
}
|
|
}
|
|
if (autoIncrement) {
|
|
// XXX unlikely race condition - t.m_id may no longer be same table
|
|
if (! m_ndb.setTupleIdInNdb(t.m_id, initialValue, false)) {
|
|
if (m_ndb.theError.code)
|
|
m_error.code = m_ndb.theError.code;
|
|
else
|
|
m_error.code = 4336;
|
|
delete t2;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// blob tables - use "t2" to get values set by kernel
|
|
if (t2->m_noOfBlobs != 0 && createBlobTables(*t2) != 0) {
|
|
int save_code = m_error.code;
|
|
(void)dropTable(*t2);
|
|
m_error.code = save_code;
|
|
delete t2;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
// not entered in cache
|
|
delete t2;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createBlobTables(NdbTableImpl &t)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::createBlobTables");
|
|
for (unsigned i = 0; i < t.m_columns.size(); i++) {
|
|
NdbColumnImpl & c = *t.m_columns[i];
|
|
if (! c.getBlobType() || c.getPartSize() == 0)
|
|
continue;
|
|
NdbTableImpl bt;
|
|
NdbBlob::getBlobTable(bt, &t, &c);
|
|
if (createTable(bt) != 0) {
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::createTable(Ndb & ndb,
|
|
NdbTableImpl & impl)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::createTable");
|
|
DBUG_RETURN(createOrAlterTable(ndb, impl, false));
|
|
}
|
|
|
|
int NdbDictionaryImpl::alterTable(NdbTableImpl &impl)
|
|
{
|
|
BaseString internalName(impl.m_internalName);
|
|
const char * originalInternalName = internalName.c_str();
|
|
|
|
DBUG_ENTER("NdbDictionaryImpl::alterTable");
|
|
Ndb_local_table_info * local = 0;
|
|
if((local= get_local_table_info(originalInternalName)) == 0)
|
|
{
|
|
m_error.code = 709;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
// Alter the table
|
|
int ret = alterTableGlobal(*local->m_table_impl, impl);
|
|
if(ret == 0)
|
|
{
|
|
m_globalHash->lock();
|
|
m_globalHash->release(local->m_table_impl, 1);
|
|
m_globalHash->unlock();
|
|
m_localHash.drop(originalInternalName);
|
|
}
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
int NdbDictionaryImpl::alterTableGlobal(NdbTableImpl &old_impl,
|
|
NdbTableImpl &impl)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::alterTableGlobal");
|
|
// Alter the table
|
|
int ret = m_receiver.alterTable(m_ndb, impl);
|
|
old_impl.m_status = NdbDictionary::Object::Invalid;
|
|
if(ret == 0){
|
|
DBUG_RETURN(ret);
|
|
}
|
|
ERR_RETURN(getNdbError(), ret);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::alterTable(Ndb & ndb,
|
|
NdbTableImpl & impl)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::alterTable");
|
|
DBUG_RETURN(createOrAlterTable(ndb, impl, true));
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::createOrAlterTable(Ndb & ndb,
|
|
NdbTableImpl & impl,
|
|
bool alter)
|
|
{
|
|
unsigned i, err;
|
|
char *ts_names[MAX_NDB_PARTITIONS];
|
|
DBUG_ENTER("NdbDictInterface::createOrAlterTable");
|
|
|
|
impl.computeAggregates();
|
|
|
|
if((unsigned)impl.getNoOfPrimaryKeys() > NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY){
|
|
m_error.code= 4317;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
unsigned sz = impl.m_columns.size();
|
|
if (sz > NDB_MAX_ATTRIBUTES_IN_TABLE){
|
|
m_error.code= 4318;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
// Check if any changes for alter table
|
|
|
|
// Name change
|
|
if (!impl.m_newExternalName.empty()) {
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setNameFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_externalName.assign(impl.m_newExternalName);
|
|
impl.m_newExternalName.clear();
|
|
}
|
|
// Definition change (frm)
|
|
if (!impl.m_newFrm.empty())
|
|
{
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setFrmFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_frm.assign(impl.m_newFrm.get_data(), impl.m_newFrm.length());
|
|
impl.m_newFrm.clear();
|
|
}
|
|
// Change FragmentData (fragment identity, state, tablespace id)
|
|
if (!impl.m_new_fd.empty())
|
|
{
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setFragDataFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_fd.assign(impl.m_new_fd.get_data(), impl.m_new_fd.length());
|
|
impl.m_new_fd.clear();
|
|
}
|
|
// Change Tablespace Name Data
|
|
if (!impl.m_new_ts_name.empty())
|
|
{
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setTsNameFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_ts_name.assign(impl.m_new_ts_name.get_data(),
|
|
impl.m_new_ts_name.length());
|
|
impl.m_new_ts_name.clear();
|
|
}
|
|
// Change Range/List Data
|
|
if (!impl.m_new_range.empty())
|
|
{
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setRangeListFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_range.assign(impl.m_new_range.get_data(),
|
|
impl.m_new_range.length());
|
|
impl.m_new_range.clear();
|
|
}
|
|
// Change Tablespace Data
|
|
if (!impl.m_new_ts.empty())
|
|
{
|
|
if (alter)
|
|
{
|
|
AlterTableReq::setTsFlag(impl.m_changeMask, true);
|
|
}
|
|
impl.m_ts.assign(impl.m_new_ts.get_data(),
|
|
impl.m_new_ts.length());
|
|
impl.m_new_ts.clear();
|
|
}
|
|
|
|
|
|
/*
|
|
TODO RONM: Here I need to insert checks for fragment array and
|
|
range or list array
|
|
*/
|
|
|
|
//validate();
|
|
//aggregate();
|
|
|
|
const BaseString internalName(
|
|
ndb.internalize_table_name(impl.m_externalName.c_str()));
|
|
impl.m_internalName.assign(internalName);
|
|
impl.updateMysqlName();
|
|
DictTabInfo::Table *tmpTab;
|
|
|
|
tmpTab = (DictTabInfo::Table*)NdbMem_Allocate(sizeof(DictTabInfo::Table));
|
|
if (!tmpTab)
|
|
{
|
|
m_error.code = 4000;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
tmpTab->init();
|
|
BaseString::snprintf(tmpTab->TableName,
|
|
sizeof(tmpTab->TableName),
|
|
internalName.c_str());
|
|
|
|
Uint32 distKeys= 0;
|
|
for(i = 0; i<sz; i++) {
|
|
const NdbColumnImpl * col = impl.m_columns[i];
|
|
if (col == NULL) {
|
|
m_error.code = 4272;
|
|
NdbMem_Free((void*)tmpTab);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
if (col->m_distributionKey)
|
|
{
|
|
distKeys++;
|
|
}
|
|
}
|
|
if (distKeys == impl.m_noOfKeys)
|
|
distKeys= 0;
|
|
impl.m_noOfDistributionKeys= distKeys;
|
|
|
|
|
|
// Check max length of frm data
|
|
if (impl.m_frm.length() > MAX_FRM_DATA_SIZE){
|
|
m_error.code= 1229;
|
|
NdbMem_Free((void*)tmpTab);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
/*
|
|
TODO RONM: This needs to change to dynamic arrays instead
|
|
Frm Data, FragmentData, TablespaceData, RangeListData, TsNameData
|
|
*/
|
|
tmpTab->FrmLen = impl.m_frm.length();
|
|
memcpy(tmpTab->FrmData, impl.m_frm.get_data(), impl.m_frm.length());
|
|
|
|
tmpTab->FragmentDataLen = impl.m_fd.length();
|
|
memcpy(tmpTab->FragmentData, impl.m_fd.get_data(), impl.m_fd.length());
|
|
|
|
tmpTab->TablespaceDataLen = impl.m_ts.length();
|
|
memcpy(tmpTab->TablespaceData, impl.m_ts.get_data(), impl.m_ts.length());
|
|
|
|
tmpTab->RangeListDataLen = impl.m_range.length();
|
|
memcpy(tmpTab->RangeListData, impl.m_range.get_data(),
|
|
impl.m_range.length());
|
|
|
|
memcpy(ts_names, impl.m_ts_name.get_data(),
|
|
impl.m_ts_name.length());
|
|
|
|
tmpTab->FragmentCount= impl.m_fragmentCount;
|
|
tmpTab->TableLoggedFlag = impl.m_logging;
|
|
tmpTab->RowGCIFlag = impl.m_row_gci;
|
|
tmpTab->RowChecksumFlag = impl.m_row_checksum;
|
|
tmpTab->TableKValue = impl.m_kvalue;
|
|
tmpTab->MinLoadFactor = impl.m_minLoadFactor;
|
|
tmpTab->MaxLoadFactor = impl.m_maxLoadFactor;
|
|
tmpTab->TableType = DictTabInfo::UserTable;
|
|
tmpTab->PrimaryTableId = impl.m_primaryTableId;
|
|
tmpTab->NoOfAttributes = sz;
|
|
tmpTab->MaxRowsHigh = (Uint32)(impl.m_max_rows >> 32);
|
|
tmpTab->MaxRowsLow = (Uint32)(impl.m_max_rows & 0xFFFFFFFF);
|
|
tmpTab->DefaultNoPartFlag = impl.m_default_no_part_flag;
|
|
tmpTab->LinearHashFlag = impl.m_linear_flag;
|
|
|
|
if (impl.m_ts_name.length())
|
|
{
|
|
char **ts_name_ptr= (char**)ts_names;
|
|
i= 0;
|
|
do
|
|
{
|
|
NdbTablespaceImpl tmp;
|
|
if (*ts_name_ptr)
|
|
{
|
|
if(get_filegroup(tmp, NdbDictionary::Object::Tablespace,
|
|
(const char*)*ts_name_ptr) == 0)
|
|
{
|
|
tmpTab->TablespaceData[2*i] = tmp.m_id;
|
|
tmpTab->TablespaceData[2*i + 1] = tmp.m_version;
|
|
}
|
|
else
|
|
{
|
|
NdbMem_Free((void*)tmpTab);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
No tablespace used, set tablespace id to NULL
|
|
*/
|
|
tmpTab->TablespaceData[2*i] = RNIL;
|
|
tmpTab->TablespaceData[2*i + 1] = 0;
|
|
}
|
|
ts_name_ptr++;
|
|
} while (++i < tmpTab->FragmentCount);
|
|
tmpTab->TablespaceDataLen= 4*i;
|
|
}
|
|
|
|
tmpTab->FragmentType = getKernelConstant(impl.m_fragmentType,
|
|
fragmentTypeMapping,
|
|
DictTabInfo::AllNodesSmallTable);
|
|
tmpTab->TableVersion = rand();
|
|
|
|
const char *tablespace_name= impl.m_tablespace_name.c_str();
|
|
loop:
|
|
if(impl.m_tablespace_id != ~(Uint32)0)
|
|
{
|
|
tmpTab->TablespaceId = impl.m_tablespace_id;
|
|
tmpTab->TablespaceVersion = impl.m_tablespace_version;
|
|
}
|
|
else if(strlen(tablespace_name))
|
|
{
|
|
NdbTablespaceImpl tmp;
|
|
if(get_filegroup(tmp, NdbDictionary::Object::Tablespace,
|
|
tablespace_name) == 0)
|
|
{
|
|
tmpTab->TablespaceId = tmp.m_id;
|
|
tmpTab->TablespaceVersion = tmp.m_version;
|
|
}
|
|
else
|
|
{
|
|
// error set by get filegroup
|
|
NdbMem_Free((void*)tmpTab);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; i<sz; i++)
|
|
{
|
|
if(impl.m_columns[i]->m_storageType == NDB_STORAGETYPE_DISK)
|
|
{
|
|
tablespace_name = "DEFAULT-TS";
|
|
goto loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
UtilBufferWriter w(m_buffer);
|
|
SimpleProperties::UnpackStatus s;
|
|
s = SimpleProperties::pack(w,
|
|
tmpTab,
|
|
DictTabInfo::TableMapping,
|
|
DictTabInfo::TableMappingSize, true);
|
|
|
|
if(s != SimpleProperties::Eof){
|
|
abort();
|
|
}
|
|
NdbMem_Free((void*)tmpTab);
|
|
|
|
DBUG_PRINT("info",("impl.m_noOfDistributionKeys: %d impl.m_noOfKeys: %d distKeys: %d",
|
|
impl.m_noOfDistributionKeys, impl.m_noOfKeys, distKeys));
|
|
if (distKeys == impl.m_noOfKeys)
|
|
distKeys= 0;
|
|
impl.m_noOfDistributionKeys= distKeys;
|
|
|
|
for(i = 0; i<sz; i++){
|
|
const NdbColumnImpl * col = impl.m_columns[i];
|
|
if(col == 0)
|
|
continue;
|
|
|
|
DBUG_PRINT("info",("column: %s(%d) col->m_distributionKey: %d",
|
|
col->m_name.c_str(), i, col->m_distributionKey));
|
|
DictTabInfo::Attribute tmpAttr; tmpAttr.init();
|
|
BaseString::snprintf(tmpAttr.AttributeName, sizeof(tmpAttr.AttributeName),
|
|
col->m_name.c_str());
|
|
tmpAttr.AttributeId = col->m_attrId;
|
|
tmpAttr.AttributeKeyFlag = col->m_pk;
|
|
tmpAttr.AttributeNullableFlag = col->m_nullable;
|
|
tmpAttr.AttributeDKey = distKeys ? (bool)col->m_distributionKey : 0;
|
|
|
|
tmpAttr.AttributeExtType = (Uint32)col->m_type;
|
|
tmpAttr.AttributeExtPrecision = ((unsigned)col->m_precision & 0xFFFF);
|
|
tmpAttr.AttributeExtScale = col->m_scale;
|
|
tmpAttr.AttributeExtLength = col->m_length;
|
|
if(col->m_storageType == NDB_STORAGETYPE_DISK)
|
|
tmpAttr.AttributeArrayType = NDB_ARRAYTYPE_FIXED;
|
|
else
|
|
tmpAttr.AttributeArrayType = col->m_arrayType;
|
|
|
|
if(col->m_pk)
|
|
tmpAttr.AttributeStorageType = NDB_STORAGETYPE_MEMORY;
|
|
else
|
|
tmpAttr.AttributeStorageType = col->m_storageType;
|
|
|
|
if(col->getBlobType())
|
|
tmpAttr.AttributeStorageType = NDB_STORAGETYPE_MEMORY;
|
|
|
|
// check type and compute attribute size and array size
|
|
if (! tmpAttr.translateExtType()) {
|
|
m_error.code= 703;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
// charset is defined exactly for char types
|
|
if (col->getCharType() != (col->m_cs != NULL)) {
|
|
m_error.code= 703;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
// primary key type check
|
|
if (col->m_pk &&
|
|
(err = NdbSqlUtil::check_column_for_pk(col->m_type, col->m_cs)))
|
|
{
|
|
m_error.code= err;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
// distribution key not supported for Char attribute
|
|
if (distKeys && col->m_distributionKey && col->m_cs != NULL) {
|
|
// we can allow this for non-var char where strxfrm does nothing
|
|
if (col->m_type == NdbDictionary::Column::Char &&
|
|
(col->m_cs->state & MY_CS_BINSORT))
|
|
;
|
|
else {
|
|
m_error.code= 745;
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
// charset in upper half of precision
|
|
if (col->getCharType()) {
|
|
tmpAttr.AttributeExtPrecision |= (col->m_cs->number << 16);
|
|
}
|
|
|
|
tmpAttr.AttributeAutoIncrement = col->m_autoIncrement;
|
|
BaseString::snprintf(tmpAttr.AttributeDefaultValue,
|
|
sizeof(tmpAttr.AttributeDefaultValue),
|
|
col->m_defaultValue.c_str());
|
|
s = SimpleProperties::pack(w,
|
|
&tmpAttr,
|
|
DictTabInfo::AttributeMapping,
|
|
DictTabInfo::AttributeMappingSize, true);
|
|
w.add(DictTabInfo::AttributeEnd, 1);
|
|
}
|
|
|
|
int ret;
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz = m_buffer.length() / 4;
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
if (alter) {
|
|
tSignal.theVerId_signalNumber = GSN_ALTER_TABLE_REQ;
|
|
tSignal.theLength = AlterTableReq::SignalLength;
|
|
|
|
AlterTableReq * req = CAST_PTR(AlterTableReq, tSignal.getDataPtrSend());
|
|
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->changeMask = impl.m_changeMask;
|
|
req->tableId = impl.m_id;
|
|
req->tableVersion = impl.m_version;;
|
|
|
|
int errCodes[] = { AlterTableRef::NotMaster, AlterTableRef::Busy, 0 };
|
|
ret = dictSignal(&tSignal, ptr, 1,
|
|
0, // master
|
|
WAIT_ALTER_TAB_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
errCodes);
|
|
|
|
if(m_error.code == AlterTableRef::InvalidTableVersion) {
|
|
// Clear caches and try again
|
|
DBUG_RETURN(INCOMPATIBLE_VERSION);
|
|
}
|
|
} else {
|
|
tSignal.theVerId_signalNumber = GSN_CREATE_TABLE_REQ;
|
|
tSignal.theLength = CreateTableReq::SignalLength;
|
|
|
|
CreateTableReq * req = CAST_PTR(CreateTableReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
int errCodes[] = { CreateTableRef::Busy, CreateTableRef::NotMaster, 0 };
|
|
ret = dictSignal(&tSignal, ptr, 1,
|
|
0, // master node
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
errCodes);
|
|
}
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_TABLE_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const CreateTableConf* const conf=
|
|
CAST_CONSTPTR(CreateTableConf, signal->getDataPtr());
|
|
m_buffer.grow(4 * 2); // 2 words
|
|
Uint32* data = (Uint32*)m_buffer.get_data();
|
|
data[0] = conf->tableId;
|
|
data[1] = conf->tableVersion;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_TABLE_REF(NdbApiSignal * sig,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const CreateTableRef* ref = CAST_CONSTPTR(CreateTableRef, sig->getDataPtr());
|
|
m_error.code= ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execALTER_TABLE_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execALTER_TABLE_REF(NdbApiSignal * sig,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const AlterTableRef * ref = CAST_CONSTPTR(AlterTableRef, sig->getDataPtr());
|
|
m_error.code= ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Drop table
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::dropTable(const char * name)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::dropTable");
|
|
DBUG_PRINT("enter",("name: %s", name));
|
|
ASSERT_NOT_MYSQLD;
|
|
NdbTableImpl * tab = getTable(name);
|
|
if(tab == 0){
|
|
DBUG_RETURN(-1);
|
|
}
|
|
int ret = dropTable(* tab);
|
|
// If table stored in cache is incompatible with the one in the kernel
|
|
// we must clear the cache and try again
|
|
if (ret == INCOMPATIBLE_VERSION) {
|
|
const BaseString internalTableName(m_ndb.internalize_table_name(name));
|
|
DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName.c_str()));
|
|
m_localHash.drop(internalTableName.c_str());
|
|
m_globalHash->lock();
|
|
m_globalHash->release(tab, 1);
|
|
m_globalHash->unlock();
|
|
DBUG_RETURN(dropTable(name));
|
|
}
|
|
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropTable(NdbTableImpl & impl)
|
|
{
|
|
int res;
|
|
const char * name = impl.getName();
|
|
if(impl.m_status == NdbDictionary::Object::New){
|
|
return dropTable(name);
|
|
}
|
|
|
|
if (impl.m_indexType != NdbDictionary::Object::TypeUndefined)
|
|
{
|
|
m_receiver.m_error.code= 1228;
|
|
return -1;
|
|
}
|
|
|
|
List list;
|
|
if ((res = listIndexes(list, impl.m_id)) == -1){
|
|
return -1;
|
|
}
|
|
for (unsigned i = 0; i < list.count; i++) {
|
|
const List::Element& element = list.elements[i];
|
|
if ((res = 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 || m_error.code == 709 || m_error.code == 723){
|
|
const char * internalTableName = impl.m_internalName.c_str();
|
|
|
|
|
|
m_localHash.drop(internalTableName);
|
|
m_globalHash->lock();
|
|
m_globalHash->release(&impl, 1);
|
|
m_globalHash->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropTableGlobal(NdbTableImpl & impl)
|
|
{
|
|
int res;
|
|
const char * name = impl.getName();
|
|
DBUG_ENTER("NdbDictionaryImpl::dropTableGlobal");
|
|
DBUG_ASSERT(impl.m_status != NdbDictionary::Object::New);
|
|
DBUG_ASSERT(impl.m_indexType == NdbDictionary::Object::TypeUndefined);
|
|
|
|
List list;
|
|
if ((res = listIndexes(list, impl.m_id)) == -1){
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
for (unsigned i = 0; i < list.count; i++) {
|
|
const List::Element& element = list.elements[i];
|
|
NdbIndexImpl *idx= getIndexGlobal(element.name, impl);
|
|
if (idx == NULL)
|
|
{
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
if ((res = dropIndexGlobal(*idx)) == -1)
|
|
{
|
|
releaseIndexGlobal(*idx, 1);
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
releaseIndexGlobal(*idx, 1);
|
|
}
|
|
|
|
if (impl.m_noOfBlobs != 0) {
|
|
if (dropBlobTables(impl) != 0){
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
}
|
|
|
|
int ret = m_receiver.dropTable(impl);
|
|
impl.m_status = NdbDictionary::Object::Invalid;
|
|
if(ret == 0 || m_error.code == 709 || m_error.code == 723)
|
|
{
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
ERR_RETURN(getNdbError(), ret);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropBlobTables(NdbTableImpl & t)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::dropBlobTables");
|
|
for (unsigned i = 0; i < t.m_columns.size(); i++) {
|
|
NdbColumnImpl & c = *t.m_columns[i];
|
|
if (! c.getBlobType() || c.getPartSize() == 0)
|
|
continue;
|
|
NdbTableImpl* bt = c.m_blobTable;
|
|
if (bt == NULL) {
|
|
DBUG_PRINT("info", ("col %s: blob table pointer is NULL",
|
|
c.m_name.c_str()));
|
|
continue; // "force" mode on
|
|
}
|
|
// drop directly - by-pass cache
|
|
int ret = m_receiver.dropTable(*c.m_blobTable);
|
|
if (ret != 0) {
|
|
DBUG_PRINT("info", ("col %s: blob table %s: error %d",
|
|
c.m_name.c_str(), bt->m_internalName.c_str(), m_error.code));
|
|
if (! (ret == 709 || ret == 723)) // "force" mode on
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
// leave c.m_blobTable defined
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::dropTable(const NdbTableImpl & impl)
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_DROP_TABLE_REQ;
|
|
tSignal.theLength = DropTableReq::SignalLength;
|
|
|
|
DropTableReq * req = CAST_PTR(DropTableReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->tableId = impl.m_id;
|
|
req->tableVersion = impl.m_version;
|
|
|
|
int errCodes[] =
|
|
{ DropTableRef::NoDropTableRecordAvailable,
|
|
DropTableRef::NotMaster,
|
|
DropTableRef::Busy, 0 };
|
|
int r = dictSignal(&tSignal, 0, 0,
|
|
0, // master
|
|
WAIT_DROP_TAB_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
errCodes);
|
|
if(m_error.code == DropTableRef::InvalidTableVersion) {
|
|
// Clear caches and try again
|
|
return INCOMPATIBLE_VERSION;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_TABLE_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execDROP_TABLE_CONF");
|
|
//DropTableConf* const conf = CAST_CONSTPTR(DropTableConf, signal->getDataPtr());
|
|
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_TABLE_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execDROP_TABLE_REF");
|
|
const DropTableRef* ref = CAST_CONSTPTR(DropTableRef, signal->getDataPtr());
|
|
m_error.code= ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl)
|
|
{
|
|
const char * internalTableName = impl.m_internalName.c_str();
|
|
DBUG_ENTER("NdbDictionaryImpl::invalidateObject");
|
|
DBUG_PRINT("enter", ("internal_name: %s", internalTableName));
|
|
|
|
m_localHash.drop(internalTableName);
|
|
m_globalHash->lock();
|
|
m_globalHash->release(&impl, 1);
|
|
m_globalHash->unlock();
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl)
|
|
{
|
|
const char * internalTableName = impl.m_internalName.c_str();
|
|
DBUG_ENTER("NdbDictionaryImpl::removeCachedObject");
|
|
DBUG_PRINT("enter", ("internal_name: %s", internalTableName));
|
|
|
|
m_localHash.drop(internalTableName);
|
|
m_globalHash->lock();
|
|
m_globalHash->release(&impl);
|
|
m_globalHash->unlock();
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
|
|
NdbTableImpl* tab,
|
|
const NdbTableImpl* prim)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::create_index_obj_from_table");
|
|
NdbIndexImpl *idx = new NdbIndexImpl();
|
|
idx->m_version = tab->m_version;
|
|
idx->m_status = tab->m_status;
|
|
idx->m_id = tab->m_id;
|
|
idx->m_externalName.assign(tab->getName());
|
|
idx->m_tableName.assign(prim->m_externalName);
|
|
NdbDictionary::Object::Type type = idx->m_type = tab->m_indexType;
|
|
idx->m_logging = tab->m_logging;
|
|
// skip last attribute (NDB$PK or NDB$TNODE)
|
|
|
|
const Uint32 distKeys = prim->m_noOfDistributionKeys;
|
|
Uint32 keyCount = (distKeys ? distKeys : prim->m_noOfKeys);
|
|
|
|
unsigned i;
|
|
for(i = 0; i+1<tab->m_columns.size(); i++){
|
|
NdbColumnImpl* org = tab->m_columns[i];
|
|
|
|
NdbColumnImpl* col = new NdbColumnImpl;
|
|
// Copy column definition
|
|
*col = * org;
|
|
idx->m_columns.push_back(col);
|
|
|
|
/**
|
|
* reverse map
|
|
*/
|
|
const NdbColumnImpl* primCol = prim->getColumn(col->getName());
|
|
int key_id = primCol->getColumnNo();
|
|
int fill = -1;
|
|
idx->m_key_ids.fill(key_id, fill);
|
|
idx->m_key_ids[key_id] = i;
|
|
col->m_keyInfoPos = key_id;
|
|
|
|
if(type == NdbDictionary::Object::OrderedIndex &&
|
|
(primCol->m_distributionKey ||
|
|
(distKeys == 0 && primCol->getPrimaryKey())))
|
|
{
|
|
keyCount--;
|
|
org->m_distributionKey = 1;
|
|
}
|
|
}
|
|
|
|
if(keyCount == 0)
|
|
{
|
|
tab->m_noOfDistributionKeys = (distKeys ? distKeys : prim->m_noOfKeys);
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; i+1<tab->m_columns.size(); i++)
|
|
tab->m_columns[i]->m_distributionKey = 0;
|
|
}
|
|
|
|
idx->m_table_id = prim->getObjectId();
|
|
idx->m_table_version = prim->getObjectVersion();
|
|
|
|
* dst = idx;
|
|
DBUG_PRINT("exit", ("m_id: %d m_version: %d", idx->m_id, idx->m_version));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Create index
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::createIndex(NdbIndexImpl &ix)
|
|
{
|
|
ASSERT_NOT_MYSQLD;
|
|
NdbTableImpl* tab = getTable(ix.getTable());
|
|
if(tab == 0){
|
|
m_error.code = 4249;
|
|
return -1;
|
|
}
|
|
|
|
return m_receiver.createIndex(m_ndb, ix, * tab);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createIndex(NdbIndexImpl &ix, NdbTableImpl &tab)
|
|
{
|
|
return m_receiver.createIndex(m_ndb, ix, tab);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::createIndex(Ndb & ndb,
|
|
const NdbIndexImpl & impl,
|
|
const NdbTableImpl & table)
|
|
{
|
|
//validate();
|
|
//aggregate();
|
|
unsigned i, err;
|
|
UtilBufferWriter w(m_buffer);
|
|
const size_t len = strlen(impl.m_externalName.c_str()) + 1;
|
|
if(len > MAX_TAB_NAME_SIZE) {
|
|
m_error.code = 4241;
|
|
return -1;
|
|
}
|
|
const BaseString internalName(
|
|
ndb.internalize_index_name(&table, impl.getName()));
|
|
w.add(DictTabInfo::TableName, internalName.c_str());
|
|
w.add(DictTabInfo::TableLoggedFlag, impl.m_logging);
|
|
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_CREATE_INDX_REQ;
|
|
tSignal.theLength = CreateIndxReq::SignalLength;
|
|
|
|
CreateIndxReq * const req = CAST_PTR(CreateIndxReq, tSignal.getDataPtrSend());
|
|
|
|
req->setUserRef(m_reference);
|
|
req->setConnectionPtr(0);
|
|
req->setRequestType(CreateIndxReq::RT_USER);
|
|
|
|
Uint32 it = getKernelConstant(impl.m_type,
|
|
indexTypeMapping,
|
|
DictTabInfo::UndefTableType);
|
|
|
|
if(it == DictTabInfo::UndefTableType){
|
|
m_error.code = 4250;
|
|
return -1;
|
|
}
|
|
req->setIndexType((DictTabInfo::TableType) it);
|
|
|
|
req->setTableId(table.m_id);
|
|
req->setOnline(true);
|
|
AttributeList attributeList;
|
|
attributeList.sz = impl.m_columns.size();
|
|
for(i = 0; i<attributeList.sz; i++){
|
|
const NdbColumnImpl* col =
|
|
table.getColumn(impl.m_columns[i]->m_name.c_str());
|
|
if(col == 0){
|
|
m_error.code = 4247;
|
|
return -1;
|
|
}
|
|
// Copy column definition XXX must be wrong, overwrites
|
|
*impl.m_columns[i] = *col;
|
|
|
|
// index key type check
|
|
if (it == DictTabInfo::UniqueHashIndex &&
|
|
(err = NdbSqlUtil::check_column_for_hash_index(col->m_type, col->m_cs))
|
|
||
|
|
it == DictTabInfo::OrderedIndex &&
|
|
(err = NdbSqlUtil::check_column_for_ordered_index(col->m_type, col->m_cs)))
|
|
{
|
|
m_error.code = err;
|
|
return -1;
|
|
}
|
|
// API uses external column number to talk to DICT
|
|
attributeList.id[i] = col->m_column_no;
|
|
}
|
|
LinearSectionPtr ptr[2];
|
|
ptr[0].p = (Uint32*)&attributeList;
|
|
ptr[0].sz = 1 + attributeList.sz;
|
|
ptr[1].p = (Uint32*)m_buffer.get_data();
|
|
ptr[1].sz = m_buffer.length() >> 2; //BUG?
|
|
|
|
int errCodes[] = { CreateIndxRef::Busy, CreateIndxRef::NotMaster, 0 };
|
|
return dictSignal(&tSignal, ptr, 2,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
errCodes);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_INDX_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_INDX_REF(NdbApiSignal * sig,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const CreateIndxRef* ref = CAST_CONSTPTR(CreateIndxRef, sig->getDataPtr());
|
|
m_error.code = ref->getErrorCode();
|
|
if(m_error.code == ref->NotMaster)
|
|
m_masterNodeId= ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Drop index
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::dropIndex(const char * indexName,
|
|
const char * tableName)
|
|
{
|
|
ASSERT_NOT_MYSQLD;
|
|
NdbIndexImpl * idx = getIndex(indexName, tableName);
|
|
if (idx == 0) {
|
|
m_error.code = 4243;
|
|
return -1;
|
|
}
|
|
int ret = dropIndex(*idx, tableName);
|
|
// If index stored in cache is incompatible with the one in the kernel
|
|
// we must clear the cache and try again
|
|
if (ret == INCOMPATIBLE_VERSION) {
|
|
const BaseString internalIndexName((tableName)
|
|
?
|
|
m_ndb.internalize_index_name(getTable(tableName), indexName)
|
|
:
|
|
m_ndb.internalize_table_name(indexName)); // Index is also a table
|
|
|
|
m_localHash.drop(internalIndexName.c_str());
|
|
m_globalHash->lock();
|
|
m_globalHash->release(idx->m_table, 1);
|
|
m_globalHash->unlock();
|
|
return dropIndex(indexName, tableName);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName)
|
|
{
|
|
const char * indexName = impl.getName();
|
|
if (tableName || m_ndb.usingFullyQualifiedNames()) {
|
|
NdbTableImpl * timpl = impl.m_table;
|
|
|
|
if (timpl == 0) {
|
|
m_error.code = 709;
|
|
return -1;
|
|
}
|
|
|
|
const BaseString internalIndexName((tableName)
|
|
?
|
|
m_ndb.internalize_index_name(getTable(tableName), indexName)
|
|
:
|
|
m_ndb.internalize_table_name(indexName)); // Index is also a table
|
|
|
|
if(impl.m_status == NdbDictionary::Object::New){
|
|
return dropIndex(indexName, tableName);
|
|
}
|
|
|
|
int ret= dropIndexGlobal(impl);
|
|
if (ret == 0)
|
|
{
|
|
m_globalHash->lock();
|
|
m_globalHash->release(impl.m_table, 1);
|
|
m_globalHash->unlock();
|
|
m_localHash.drop(internalIndexName.c_str());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
m_error.code = 4243;
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropIndexGlobal(NdbIndexImpl & impl)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::dropIndexGlobal");
|
|
int ret = m_receiver.dropIndex(impl, *impl.m_table);
|
|
impl.m_status = NdbDictionary::Object::Invalid;
|
|
if(ret == 0)
|
|
{
|
|
DBUG_RETURN(0);
|
|
}
|
|
ERR_RETURN(getNdbError(), ret);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::dropIndex(const NdbIndexImpl & impl,
|
|
const NdbTableImpl & timpl)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::dropIndex");
|
|
DBUG_PRINT("enter", ("indexId: %d indexVersion: %d",
|
|
timpl.m_id, timpl.m_version));
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_DROP_INDX_REQ;
|
|
tSignal.theLength = DropIndxReq::SignalLength;
|
|
|
|
DropIndxReq * const req = CAST_PTR(DropIndxReq, tSignal.getDataPtrSend());
|
|
req->setUserRef(m_reference);
|
|
req->setConnectionPtr(0);
|
|
req->setRequestType(DropIndxReq::RT_USER);
|
|
req->setTableId(~0); // DICT overwrites
|
|
req->setIndexId(timpl.m_id);
|
|
req->setIndexVersion(timpl.m_version);
|
|
|
|
int errCodes[] = { DropIndxRef::Busy, DropIndxRef::NotMaster, 0 };
|
|
int r = dictSignal(&tSignal, 0, 0,
|
|
0, // master
|
|
WAIT_DROP_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
errCodes);
|
|
if(m_error.code == DropIndxRef::InvalidIndexVersion) {
|
|
// Clear caches and try again
|
|
ERR_RETURN(m_error, INCOMPATIBLE_VERSION);
|
|
}
|
|
ERR_RETURN(m_error, r);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_INDX_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_INDX_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const DropIndxRef* ref = CAST_CONSTPTR(DropIndxRef, signal->getDataPtr());
|
|
m_error.code = ref->getErrorCode();
|
|
if(m_error.code == ref->NotMaster)
|
|
m_masterNodeId= ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Create event
|
|
*/
|
|
|
|
int
|
|
NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::createEvent");
|
|
int i;
|
|
NdbTableImpl* tab= evnt.m_tableImpl;
|
|
if (tab == 0)
|
|
{
|
|
tab= getTable(evnt.getTableName());
|
|
if(tab == 0){
|
|
DBUG_PRINT("info",("NdbDictionaryImpl::createEvent: table not found: %s",
|
|
evnt.getTableName()));
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
evnt.setTable(tab);
|
|
}
|
|
|
|
DBUG_PRINT("info",("Table: id: %d version: %d", tab->m_id, tab->m_version));
|
|
|
|
NdbTableImpl &table = *evnt.m_tableImpl;
|
|
|
|
int attributeList_sz = evnt.m_attrIds.size();
|
|
|
|
for (i = 0; i < attributeList_sz; i++) {
|
|
NdbColumnImpl *col_impl = table.getColumn(evnt.m_attrIds[i]);
|
|
if (col_impl) {
|
|
evnt.m_facade->addColumn(*(col_impl->m_facade));
|
|
} else {
|
|
ndbout_c("Attr id %u in table %s not found", evnt.m_attrIds[i],
|
|
evnt.getTableName());
|
|
m_error.code= 4713;
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
}
|
|
|
|
evnt.m_attrIds.clear();
|
|
|
|
attributeList_sz = evnt.m_columns.size();
|
|
|
|
DBUG_PRINT("info",("Event on tableId=%d, tableVersion=%d, event name %s, no of columns %d",
|
|
table.m_id, table.m_version,
|
|
evnt.m_name.c_str(),
|
|
evnt.m_columns.size()));
|
|
|
|
int pk_count = 0;
|
|
evnt.m_attrListBitmask.clear();
|
|
|
|
for(i = 0; i<attributeList_sz; i++){
|
|
const NdbColumnImpl* col =
|
|
table.getColumn(evnt.m_columns[i]->m_name.c_str());
|
|
if(col == 0){
|
|
m_error.code= 4247;
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
// Copy column definition
|
|
*evnt.m_columns[i] = *col;
|
|
|
|
if(col->m_pk){
|
|
pk_count++;
|
|
}
|
|
|
|
evnt.m_attrListBitmask.set(col->m_attrId);
|
|
}
|
|
|
|
// Sort index attributes according to primary table (using insertion sort)
|
|
for(i = 1; i < attributeList_sz; i++) {
|
|
NdbColumnImpl* temp = evnt.m_columns[i];
|
|
unsigned int j = i;
|
|
while((j > 0) && (evnt.m_columns[j - 1]->m_attrId > temp->m_attrId)) {
|
|
evnt.m_columns[j] = evnt.m_columns[j - 1];
|
|
j--;
|
|
}
|
|
evnt.m_columns[j] = temp;
|
|
}
|
|
// Check for illegal duplicate attributes
|
|
for(i = 1; i<attributeList_sz; i++) {
|
|
if (evnt.m_columns[i-1]->m_attrId == evnt.m_columns[i]->m_attrId) {
|
|
m_error.code= 4258;
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
}
|
|
|
|
#ifdef EVENT_DEBUG
|
|
char buf[128] = {0};
|
|
evnt.m_attrListBitmask.getText(buf);
|
|
ndbout_c("createEvent: mask = %s", buf);
|
|
#endif
|
|
|
|
// NdbDictInterface m_receiver;
|
|
if (m_receiver.createEvent(m_ndb, evnt, 0 /* getFlag unset */) != 0)
|
|
ERR_RETURN(getNdbError(), -1);
|
|
|
|
// Create blob events
|
|
if (evnt.m_mergeEvents && createBlobEvents(evnt) != 0) {
|
|
int save_code = m_error.code;
|
|
(void)dropEvent(evnt.m_name.c_str());
|
|
m_error.code = save_code;
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createBlobEvents(NdbEventImpl& evnt)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::createBlobEvents");
|
|
NdbTableImpl& t = *evnt.m_tableImpl;
|
|
Uint32 n = t.m_noOfBlobs;
|
|
Uint32 i;
|
|
for (i = 0; i < evnt.m_columns.size() && n > 0; i++) {
|
|
NdbColumnImpl & c = *evnt.m_columns[i];
|
|
if (! c.getBlobType() || c.getPartSize() == 0)
|
|
continue;
|
|
n--;
|
|
NdbEventImpl blob_evnt;
|
|
NdbBlob::getBlobEvent(blob_evnt, &evnt, &c);
|
|
if (createEvent(blob_evnt) != 0)
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::createEvent(class Ndb & ndb,
|
|
NdbEventImpl & evnt,
|
|
int getFlag)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::createEvent");
|
|
DBUG_PRINT("enter",("getFlag=%d",getFlag));
|
|
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_CREATE_EVNT_REQ;
|
|
if (getFlag)
|
|
tSignal.theLength = CreateEvntReq::SignalLengthGet;
|
|
else
|
|
tSignal.theLength = CreateEvntReq::SignalLengthCreate;
|
|
|
|
CreateEvntReq * const req = CAST_PTR(CreateEvntReq, tSignal.getDataPtrSend());
|
|
|
|
req->setUserRef(m_reference);
|
|
req->setUserData(0);
|
|
|
|
if (getFlag) {
|
|
// getting event from Dictionary
|
|
req->setRequestType(CreateEvntReq::RT_USER_GET);
|
|
} else {
|
|
DBUG_PRINT("info",("tableId: %u tableVersion: %u",
|
|
evnt.m_tableImpl->m_id,
|
|
evnt.m_tableImpl->m_version));
|
|
// creating event in Dictionary
|
|
req->setRequestType(CreateEvntReq::RT_USER_CREATE);
|
|
req->setTableId(evnt.m_tableImpl->m_id);
|
|
req->setTableVersion(evnt.m_tableImpl->m_version);
|
|
req->setAttrListBitmask(evnt.m_attrListBitmask);
|
|
req->setEventType(evnt.mi_type);
|
|
req->clearFlags();
|
|
if (evnt.m_rep & NdbDictionary::Event::ER_ALL)
|
|
req->setReportAll();
|
|
if (evnt.m_rep & NdbDictionary::Event::ER_SUBSCRIBE)
|
|
req->setReportSubscribe();
|
|
}
|
|
|
|
UtilBufferWriter w(m_buffer);
|
|
|
|
const size_t len = strlen(evnt.m_name.c_str()) + 1;
|
|
if(len > MAX_TAB_NAME_SIZE) {
|
|
m_error.code= 4241;
|
|
ERR_RETURN(getNdbError(), -1);
|
|
}
|
|
|
|
w.add(SimpleProperties::StringValue, evnt.m_name.c_str());
|
|
|
|
if (getFlag == 0)
|
|
{
|
|
const BaseString internal_tabname(
|
|
ndb.internalize_table_name(evnt.m_tableName.c_str()));
|
|
w.add(SimpleProperties::StringValue,
|
|
internal_tabname.c_str());
|
|
}
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz = (m_buffer.length()+3) >> 2;
|
|
|
|
int ret = dictSignal(&tSignal,ptr, 1,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
0, -1);
|
|
|
|
if (ret) {
|
|
ERR_RETURN(getNdbError(), ret);
|
|
}
|
|
|
|
char *dataPtr = (char *)m_buffer.get_data();
|
|
unsigned int lenCreateEvntConf = *((unsigned int *)dataPtr);
|
|
dataPtr += sizeof(lenCreateEvntConf);
|
|
CreateEvntConf const * evntConf = (CreateEvntConf *)dataPtr;
|
|
dataPtr += lenCreateEvntConf;
|
|
|
|
// NdbEventImpl *evntImpl = (NdbEventImpl *)evntConf->getUserData();
|
|
|
|
evnt.m_eventId = evntConf->getEventId();
|
|
evnt.m_eventKey = evntConf->getEventKey();
|
|
evnt.m_table_id = evntConf->getTableId();
|
|
evnt.m_table_version = evntConf->getTableVersion();
|
|
|
|
if (getFlag) {
|
|
evnt.m_attrListBitmask = evntConf->getAttrListBitmask();
|
|
evnt.mi_type = evntConf->getEventType();
|
|
evnt.setTable(dataPtr);
|
|
} else {
|
|
if (evnt.m_tableImpl->m_id != evntConf->getTableId() ||
|
|
evnt.m_tableImpl->m_version != evntConf->getTableVersion() ||
|
|
//evnt.m_attrListBitmask != evntConf->getAttrListBitmask() ||
|
|
evnt.mi_type != evntConf->getEventType()) {
|
|
ndbout_c("ERROR*************");
|
|
ERR_RETURN(getNdbError(), 1);
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::executeSubscribeEvent(NdbEventOperationImpl & ev_op)
|
|
{
|
|
// NdbDictInterface m_receiver;
|
|
return m_receiver.executeSubscribeEvent(m_ndb, ev_op);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::executeSubscribeEvent(class Ndb & ndb,
|
|
NdbEventOperationImpl & ev_op)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::executeSubscribeEvent");
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_SUB_START_REQ;
|
|
tSignal.theLength = SubStartReq::SignalLength2;
|
|
|
|
SubStartReq * req = CAST_PTR(SubStartReq, tSignal.getDataPtrSend());
|
|
|
|
req->subscriptionId = ev_op.m_eventImpl->m_eventId;
|
|
req->subscriptionKey = ev_op.m_eventImpl->m_eventKey;
|
|
req->part = SubscriptionData::TableData;
|
|
req->subscriberData = ev_op.m_oid;
|
|
req->subscriberRef = m_reference;
|
|
|
|
DBUG_PRINT("info",("GSN_SUB_START_REQ subscriptionId=%d,subscriptionKey=%d,"
|
|
"subscriberData=%d",req->subscriptionId,
|
|
req->subscriptionKey,req->subscriberData));
|
|
|
|
DBUG_RETURN(dictSignal(&tSignal,NULL,0,
|
|
0 /*use masternode id*/,
|
|
WAIT_CREATE_INDX_REQ /*WAIT_CREATE_EVNT_REQ*/,
|
|
-1, 100,
|
|
0, -1));
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::stopSubscribeEvent(NdbEventOperationImpl & ev_op)
|
|
{
|
|
// NdbDictInterface m_receiver;
|
|
return m_receiver.stopSubscribeEvent(m_ndb, ev_op);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::stopSubscribeEvent(class Ndb & ndb,
|
|
NdbEventOperationImpl & ev_op)
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::stopSubscribeEvent");
|
|
|
|
NdbApiSignal tSignal(m_reference);
|
|
// tSignal.theReceiversBlockNumber = SUMA;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_SUB_STOP_REQ;
|
|
tSignal.theLength = SubStopReq::SignalLength;
|
|
|
|
SubStopReq * req = CAST_PTR(SubStopReq, tSignal.getDataPtrSend());
|
|
|
|
req->subscriptionId = ev_op.m_eventImpl->m_eventId;
|
|
req->subscriptionKey = ev_op.m_eventImpl->m_eventKey;
|
|
req->subscriberData = ev_op.m_oid;
|
|
req->part = (Uint32) SubscriptionData::TableData;
|
|
req->subscriberRef = m_reference;
|
|
|
|
DBUG_PRINT("info",("GSN_SUB_STOP_REQ subscriptionId=%d,subscriptionKey=%d,"
|
|
"subscriberData=%d",req->subscriptionId,
|
|
req->subscriptionKey,req->subscriberData));
|
|
|
|
DBUG_RETURN(dictSignal(&tSignal,NULL,0,
|
|
0 /*use masternode id*/,
|
|
WAIT_CREATE_INDX_REQ /*WAIT_SUB_STOP__REQ*/,
|
|
-1, 100,
|
|
0, -1));
|
|
}
|
|
|
|
NdbEventImpl *
|
|
NdbDictionaryImpl::getEvent(const char * eventName, NdbTableImpl* tab)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::getEvent");
|
|
DBUG_PRINT("enter",("eventName= %s", eventName));
|
|
|
|
NdbEventImpl *ev = new NdbEventImpl();
|
|
if (ev == NULL) {
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
|
|
ev->setName(eventName);
|
|
|
|
int ret = m_receiver.createEvent(m_ndb, *ev, 1 /* getFlag set */);
|
|
|
|
if (ret) {
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
|
|
// We only have the table name with internal name
|
|
DBUG_PRINT("info",("table %s", ev->getTableName()));
|
|
if (tab == NULL)
|
|
{
|
|
tab= fetchGlobalTableImplRef(InitTable(this, ev->getTableName()));
|
|
if (tab == 0)
|
|
{
|
|
DBUG_PRINT("error",("unable to find table %s", ev->getTableName()));
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
if ((tab->m_status != NdbDictionary::Object::Retrieved) ||
|
|
(tab->m_id != ev->m_table_id) ||
|
|
(table_version_major(tab->m_version) !=
|
|
table_version_major(ev->m_table_version)))
|
|
{
|
|
DBUG_PRINT("info", ("mismatch on verison in cache"));
|
|
releaseTableGlobal(*tab, 1);
|
|
tab= fetchGlobalTableImplRef(InitTable(this, ev->getTableName()));
|
|
if (tab == 0)
|
|
{
|
|
DBUG_PRINT("error",("unable to find table %s", ev->getTableName()));
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
}
|
|
ev->setTable(tab);
|
|
releaseTableGlobal(*tab, 0);
|
|
}
|
|
else
|
|
ev->setTable(tab);
|
|
tab = 0;
|
|
|
|
ev->setTable(m_ndb.externalizeTableName(ev->getTableName()));
|
|
// get the columns from the attrListBitmask
|
|
NdbTableImpl &table = *ev->m_tableImpl;
|
|
AttributeMask & mask = ev->m_attrListBitmask;
|
|
unsigned attributeList_sz = mask.count();
|
|
|
|
DBUG_PRINT("info",("Table: id: %d version: %d",
|
|
table.m_id, table.m_version));
|
|
|
|
if (table.m_id != ev->m_table_id ||
|
|
table_version_major(table.m_version) !=
|
|
table_version_major(ev->m_table_version))
|
|
{
|
|
m_error.code = 241;
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
#ifndef DBUG_OFF
|
|
char buf[128] = {0};
|
|
mask.getText(buf);
|
|
DBUG_PRINT("info",("attributeList_sz= %d, mask= %s",
|
|
attributeList_sz, buf));
|
|
#endif
|
|
|
|
|
|
if ( attributeList_sz > table.getNoOfColumns() )
|
|
{
|
|
m_error.code = 241;
|
|
DBUG_PRINT("error",("Invalid version, too many columns"));
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
|
|
assert( (int)attributeList_sz <= table.getNoOfColumns() );
|
|
for(unsigned id= 0; ev->m_columns.size() < attributeList_sz; id++) {
|
|
if ( id >= table.getNoOfColumns())
|
|
{
|
|
m_error.code = 241;
|
|
DBUG_PRINT("error",("Invalid version, column %d out of range", id));
|
|
delete ev;
|
|
DBUG_RETURN(NULL);
|
|
}
|
|
if (!mask.get(id))
|
|
continue;
|
|
|
|
const NdbColumnImpl* col = table.getColumn(id);
|
|
DBUG_PRINT("info",("column %d %s", id, col->getName()));
|
|
NdbColumnImpl* new_col = new NdbColumnImpl;
|
|
// Copy column definition
|
|
*new_col = *col;
|
|
ev->m_columns.push_back(new_col);
|
|
}
|
|
DBUG_RETURN(ev);
|
|
}
|
|
|
|
// ev is main event and has been retrieved previously
|
|
NdbEventImpl *
|
|
NdbDictionaryImpl::getBlobEvent(const NdbEventImpl& ev, uint col_no)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::getBlobEvent");
|
|
DBUG_PRINT("enter", ("ev=%s col=%u", ev.m_name.c_str(), col_no));
|
|
|
|
NdbTableImpl* tab = ev.m_tableImpl;
|
|
assert(tab != NULL && col_no < tab->m_columns.size());
|
|
NdbColumnImpl* col = tab->m_columns[col_no];
|
|
assert(col != NULL && col->getBlobType() && col->getPartSize() != 0);
|
|
NdbTableImpl* blob_tab = col->m_blobTable;
|
|
assert(blob_tab != NULL);
|
|
char bename[MAX_TAB_NAME_SIZE];
|
|
NdbBlob::getBlobEventName(bename, &ev, col);
|
|
|
|
NdbEventImpl* blob_ev = getEvent(bename, blob_tab);
|
|
DBUG_RETURN(blob_ev);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_EVNT_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_CONF");
|
|
|
|
m_buffer.clear();
|
|
unsigned int len = signal->getLength() << 2;
|
|
m_buffer.append((char *)&len, sizeof(len));
|
|
m_buffer.append(signal->getDataPtr(), len);
|
|
|
|
if (signal->m_noOfSections > 0) {
|
|
m_buffer.append((char *)ptr[0].p, strlen((char *)ptr[0].p)+1);
|
|
}
|
|
|
|
const CreateEvntConf * const createEvntConf=
|
|
CAST_CONSTPTR(CreateEvntConf, signal->getDataPtr());
|
|
|
|
Uint32 subscriptionId = createEvntConf->getEventId();
|
|
Uint32 subscriptionKey = createEvntConf->getEventKey();
|
|
|
|
DBUG_PRINT("info",("nodeid=%d,subscriptionId=%d,subscriptionKey=%d",
|
|
refToNode(signal->theSendersBlockRef),
|
|
subscriptionId,subscriptionKey));
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_EVNT_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_REF");
|
|
|
|
const CreateEvntRef* const ref=
|
|
CAST_CONSTPTR(CreateEvntRef, signal->getDataPtr());
|
|
m_error.code= ref->getErrorCode();
|
|
DBUG_PRINT("error",("error=%d,line=%d,node=%d",ref->getErrorCode(),
|
|
ref->getErrorLine(),ref->getErrorNode()));
|
|
if (m_error.code == CreateEvntRef::NotMaster)
|
|
m_masterNodeId = ref->getMasterNode();
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execSUB_STOP_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execSUB_STOP_CONF");
|
|
const SubStopConf * const subStopConf=
|
|
CAST_CONSTPTR(SubStopConf, signal->getDataPtr());
|
|
|
|
Uint32 subscriptionId = subStopConf->subscriptionId;
|
|
Uint32 subscriptionKey = subStopConf->subscriptionKey;
|
|
Uint32 subscriberData = subStopConf->subscriberData;
|
|
|
|
DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
|
|
subscriptionId,subscriptionKey,subscriberData));
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execSUB_STOP_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execSUB_STOP_REF");
|
|
const SubStopRef * const subStopRef=
|
|
CAST_CONSTPTR(SubStopRef, signal->getDataPtr());
|
|
|
|
Uint32 subscriptionId = subStopRef->subscriptionId;
|
|
Uint32 subscriptionKey = subStopRef->subscriptionKey;
|
|
Uint32 subscriberData = subStopRef->subscriberData;
|
|
m_error.code= subStopRef->errorCode;
|
|
|
|
DBUG_PRINT("error",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d,error=%d",
|
|
subscriptionId,subscriptionKey,subscriberData,m_error.code));
|
|
if (m_error.code == SubStopRef::NotMaster)
|
|
m_masterNodeId = subStopRef->m_masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execSUB_START_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execSUB_START_CONF");
|
|
const SubStartConf * const subStartConf=
|
|
CAST_CONSTPTR(SubStartConf, signal->getDataPtr());
|
|
|
|
Uint32 subscriptionId = subStartConf->subscriptionId;
|
|
Uint32 subscriptionKey = subStartConf->subscriptionKey;
|
|
SubscriptionData::Part part =
|
|
(SubscriptionData::Part)subStartConf->part;
|
|
Uint32 subscriberData = subStartConf->subscriberData;
|
|
|
|
switch(part) {
|
|
case SubscriptionData::MetaData: {
|
|
DBUG_PRINT("error",("SubscriptionData::MetaData"));
|
|
m_error.code= 1;
|
|
break;
|
|
}
|
|
case SubscriptionData::TableData: {
|
|
DBUG_PRINT("info",("SubscriptionData::TableData"));
|
|
break;
|
|
}
|
|
default: {
|
|
DBUG_PRINT("error",("wrong data"));
|
|
m_error.code= 2;
|
|
break;
|
|
}
|
|
}
|
|
DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
|
|
subscriptionId,subscriptionKey,subscriberData));
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execSUB_START_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execSUB_START_REF");
|
|
const SubStartRef * const subStartRef=
|
|
CAST_CONSTPTR(SubStartRef, signal->getDataPtr());
|
|
m_error.code= subStartRef->errorCode;
|
|
if (m_error.code == SubStartRef::NotMaster)
|
|
m_masterNodeId = subStartRef->m_masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Drop event
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::dropEvent(const char * eventName)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::dropEvent");
|
|
DBUG_PRINT("info", ("name=%s", eventName));
|
|
|
|
NdbEventImpl *evnt = getEvent(eventName); // allocated
|
|
if (evnt == NULL) {
|
|
if (m_error.code != 723 && // no such table
|
|
m_error.code != 241) // invalid table
|
|
DBUG_RETURN(-1);
|
|
DBUG_PRINT("info", ("no table err=%d, drop by name alone", m_error.code));
|
|
evnt = new NdbEventImpl();
|
|
evnt->setName(eventName);
|
|
}
|
|
int ret = dropEvent(*evnt);
|
|
delete evnt;
|
|
DBUG_RETURN(ret);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropEvent(const NdbEventImpl& evnt)
|
|
{
|
|
if (dropBlobEvents(evnt) != 0)
|
|
return -1;
|
|
if (m_receiver.dropEvent(evnt) != 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropBlobEvents(const NdbEventImpl& evnt)
|
|
{
|
|
DBUG_ENTER("NdbDictionaryImpl::dropBlobEvents");
|
|
if (evnt.m_tableImpl != 0) {
|
|
const NdbTableImpl& t = *evnt.m_tableImpl;
|
|
Uint32 n = t.m_noOfBlobs;
|
|
Uint32 i;
|
|
for (i = 0; i < evnt.m_columns.size() && n > 0; i++) {
|
|
const NdbColumnImpl& c = *evnt.m_columns[i];
|
|
if (! c.getBlobType() || c.getPartSize() == 0)
|
|
continue;
|
|
n--;
|
|
NdbEventImpl* blob_evnt = getBlobEvent(evnt, i);
|
|
if (blob_evnt == NULL)
|
|
continue;
|
|
(void)dropEvent(*blob_evnt);
|
|
delete blob_evnt;
|
|
}
|
|
} else {
|
|
// loop over MAX_ATTRIBUTES_IN_TABLE ...
|
|
Uint32 i;
|
|
DBUG_PRINT("info", ("missing table definition, looping over "
|
|
"MAX_ATTRIBUTES_IN_TABLE(%d)",
|
|
MAX_ATTRIBUTES_IN_TABLE));
|
|
for (i = 0; i < MAX_ATTRIBUTES_IN_TABLE; i++) {
|
|
char bename[MAX_TAB_NAME_SIZE];
|
|
// XXX should get name from NdbBlob
|
|
sprintf(bename, "NDB$BLOBEVENT_%s_%u", evnt.getName(), i);
|
|
NdbEventImpl* bevnt = new NdbEventImpl();
|
|
bevnt->setName(bename);
|
|
(void)m_receiver.dropEvent(*bevnt);
|
|
delete bevnt;
|
|
}
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::dropEvent(const NdbEventImpl &evnt)
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_DROP_EVNT_REQ;
|
|
tSignal.theLength = DropEvntReq::SignalLength;
|
|
|
|
DropEvntReq * const req = CAST_PTR(DropEvntReq, tSignal.getDataPtrSend());
|
|
|
|
req->setUserRef(m_reference);
|
|
req->setUserData(0);
|
|
|
|
UtilBufferWriter w(m_buffer);
|
|
|
|
w.add(SimpleProperties::StringValue, evnt.m_name.c_str());
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz = (m_buffer.length()+3) >> 2;
|
|
|
|
return dictSignal(&tSignal,ptr, 1,
|
|
0 /*use masternode id*/,
|
|
WAIT_CREATE_INDX_REQ,
|
|
-1, 100,
|
|
0, -1);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_EVNT_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execDROP_EVNT_CONF");
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_EVNT_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
DBUG_ENTER("NdbDictInterface::execDROP_EVNT_REF");
|
|
const DropEvntRef* const ref=
|
|
CAST_CONSTPTR(DropEvntRef, signal->getDataPtr());
|
|
m_error.code= ref->getErrorCode();
|
|
|
|
DBUG_PRINT("info",("ErrorCode=%u Errorline=%u ErrorNode=%u",
|
|
ref->getErrorCode(), ref->getErrorLine(), ref->getErrorNode()));
|
|
if (m_error.code == DropEvntRef::NotMaster)
|
|
m_masterNodeId = ref->getMasterNode();
|
|
m_waiter.signal(NO_WAIT);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************
|
|
* List objects or indexes
|
|
*/
|
|
int
|
|
NdbDictionaryImpl::listObjects(List& list, NdbDictionary::Object::Type type)
|
|
{
|
|
ListTablesReq req;
|
|
req.requestData = 0;
|
|
req.setTableType(getKernelConstant(type, objectTypeMapping, 0));
|
|
req.setListNames(true);
|
|
return m_receiver.listObjects(list, req.requestData, m_ndb.usingFullyQualifiedNames());
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::listIndexes(List& list, Uint32 indexId)
|
|
{
|
|
ListTablesReq req;
|
|
req.requestData = 0;
|
|
req.setTableId(indexId);
|
|
req.setListNames(true);
|
|
req.setListIndexes(true);
|
|
return m_receiver.listObjects(list, req.requestData, m_ndb.usingFullyQualifiedNames());
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list,
|
|
Uint32 requestData, bool fullyQualifiedNames)
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
ListTablesReq* const req = CAST_PTR(ListTablesReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestData = requestData;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_LIST_TABLES_REQ;
|
|
tSignal.theLength = ListTablesReq::SignalLength;
|
|
if (listObjects(&tSignal) != 0)
|
|
return -1;
|
|
// count
|
|
const Uint32* data = (const Uint32*)m_buffer.get_data();
|
|
const unsigned length = m_buffer.length() / 4;
|
|
list.count = 0;
|
|
bool ok = true;
|
|
unsigned pos, count;
|
|
pos = count = 0;
|
|
while (pos < length) {
|
|
// table id - name length - name
|
|
pos++;
|
|
if (pos >= length) {
|
|
ok = false;
|
|
break;
|
|
}
|
|
Uint32 n = (data[pos++] + 3) >> 2;
|
|
pos += n;
|
|
if (pos > length) {
|
|
ok = false;
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
if (! ok) {
|
|
// bad signal data
|
|
m_error.code= 4213;
|
|
return -1;
|
|
}
|
|
list.count = count;
|
|
list.elements = new NdbDictionary::Dictionary::List::Element[count];
|
|
pos = count = 0;
|
|
while (pos < length) {
|
|
NdbDictionary::Dictionary::List::Element& element = list.elements[count];
|
|
Uint32 d = data[pos++];
|
|
element.id = ListTablesConf::getTableId(d);
|
|
element.type = (NdbDictionary::Object::Type)
|
|
getApiConstant(ListTablesConf::getTableType(d), objectTypeMapping, 0);
|
|
element.state = (NdbDictionary::Object::State)
|
|
getApiConstant(ListTablesConf::getTableState(d), objectStateMapping, 0);
|
|
element.store = (NdbDictionary::Object::Store)
|
|
getApiConstant(ListTablesConf::getTableStore(d), objectStoreMapping, 0);
|
|
// table or index name
|
|
Uint32 n = (data[pos++] + 3) >> 2;
|
|
BaseString databaseName;
|
|
BaseString schemaName;
|
|
BaseString objectName;
|
|
if ((element.type == NdbDictionary::Object::UniqueHashIndex) ||
|
|
(element.type == NdbDictionary::Object::OrderedIndex)) {
|
|
char * indexName = new char[n << 2];
|
|
memcpy(indexName, &data[pos], n << 2);
|
|
databaseName = Ndb::getDatabaseFromInternalName(indexName);
|
|
schemaName = Ndb::getSchemaFromInternalName(indexName);
|
|
objectName = BaseString(Ndb::externalizeIndexName(indexName, fullyQualifiedNames));
|
|
delete [] indexName;
|
|
} else if ((element.type == NdbDictionary::Object::SystemTable) ||
|
|
(element.type == NdbDictionary::Object::UserTable)) {
|
|
char * tableName = new char[n << 2];
|
|
memcpy(tableName, &data[pos], n << 2);
|
|
databaseName = Ndb::getDatabaseFromInternalName(tableName);
|
|
schemaName = Ndb::getSchemaFromInternalName(tableName);
|
|
objectName = BaseString(Ndb::externalizeTableName(tableName, fullyQualifiedNames));
|
|
delete [] tableName;
|
|
}
|
|
else {
|
|
char * otherName = new char[n << 2];
|
|
memcpy(otherName, &data[pos], n << 2);
|
|
objectName = BaseString(otherName);
|
|
delete [] otherName;
|
|
}
|
|
element.database = new char[databaseName.length() + 1];
|
|
strcpy(element.database, databaseName.c_str());
|
|
element.schema = new char[schemaName.length() + 1];
|
|
strcpy(element.schema, schemaName.c_str());
|
|
element.name = new char[objectName.length() + 1];
|
|
strcpy(element.name, objectName.c_str());
|
|
pos += n;
|
|
count++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::listObjects(NdbApiSignal* signal)
|
|
{
|
|
const Uint32 RETRIES = 100;
|
|
for (Uint32 i = 0; i < RETRIES; i++) {
|
|
m_buffer.clear();
|
|
// begin protected
|
|
/*
|
|
The PollGuard has an implicit call of unlock_and_signal through the
|
|
~PollGuard method. This method is called implicitly by the compiler
|
|
in all places where the object is out of context due to a return,
|
|
break, continue or simply end of statement block
|
|
*/
|
|
PollGuard poll_guard(m_transporter, &m_waiter, refToBlock(m_reference));
|
|
Uint16 aNodeId = m_transporter->get_an_alive_node();
|
|
if (aNodeId == 0) {
|
|
m_error.code= 4009;
|
|
return -1;
|
|
}
|
|
if (m_transporter->sendSignal(signal, aNodeId) != 0) {
|
|
continue;
|
|
}
|
|
m_error.code= 0;
|
|
int ret_val= poll_guard.wait_n_unlock(DICT_WAITFOR_TIMEOUT,
|
|
aNodeId, WAIT_LIST_TABLES_CONF);
|
|
// end protected
|
|
if (ret_val == 0 && m_error.code == 0)
|
|
return 0;
|
|
if (ret_val == -2) //WAIT_NODE_FAILURE
|
|
continue;
|
|
return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execLIST_TABLES_CONF(NdbApiSignal* signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const unsigned off = ListTablesConf::HeaderLength;
|
|
const unsigned len = (signal->getLength() - off);
|
|
m_buffer.append(signal->getDataPtr() + off, len << 2);
|
|
if (signal->getLength() < ListTablesConf::SignalLength) {
|
|
// last signal has less than full length
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::forceGCPWait()
|
|
{
|
|
return m_receiver.forceGCPWait();
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::forceGCPWait()
|
|
{
|
|
NdbApiSignal tSignal(m_reference);
|
|
WaitGCPReq* const req = CAST_PTR(WaitGCPReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestType = WaitGCPReq::CompleteForceStart;
|
|
tSignal.theReceiversBlockNumber = DBDIH;
|
|
tSignal.theVerId_signalNumber = GSN_WAIT_GCP_REQ;
|
|
tSignal.theLength = WaitGCPReq::SignalLength;
|
|
|
|
const Uint32 RETRIES = 100;
|
|
for (Uint32 i = 0; i < RETRIES; i++)
|
|
{
|
|
m_transporter->lock_mutex();
|
|
Uint16 aNodeId = m_transporter->get_an_alive_node();
|
|
if (aNodeId == 0) {
|
|
m_error.code= 4009;
|
|
m_transporter->unlock_mutex();
|
|
return -1;
|
|
}
|
|
if (m_transporter->sendSignal(&tSignal, aNodeId) != 0) {
|
|
m_transporter->unlock_mutex();
|
|
continue;
|
|
}
|
|
m_error.code= 0;
|
|
m_waiter.m_node = aNodeId;
|
|
m_waiter.m_state = WAIT_LIST_TABLES_CONF;
|
|
m_waiter.wait(DICT_WAITFOR_TIMEOUT);
|
|
m_transporter->unlock_mutex();
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execWAIT_GCP_CONF(NdbApiSignal* signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const WaitGCPConf * const conf=
|
|
CAST_CONSTPTR(WaitGCPConf, signal->getDataPtr());
|
|
g_latest_trans_gci= conf->gcp;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execWAIT_GCP_REF(NdbApiSignal* signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
NdbFilegroupImpl::NdbFilegroupImpl(NdbDictionary::Object::Type t)
|
|
: NdbDictObjectImpl(t)
|
|
{
|
|
m_extent_size = 0;
|
|
m_undo_buffer_size = 0;
|
|
m_logfile_group_id = ~0;
|
|
m_logfile_group_version = ~0;
|
|
}
|
|
|
|
NdbTablespaceImpl::NdbTablespaceImpl() :
|
|
NdbDictionary::Tablespace(* this),
|
|
NdbFilegroupImpl(NdbDictionary::Object::Tablespace), m_facade(this)
|
|
{
|
|
}
|
|
|
|
NdbTablespaceImpl::NdbTablespaceImpl(NdbDictionary::Tablespace & f) :
|
|
NdbDictionary::Tablespace(* this),
|
|
NdbFilegroupImpl(NdbDictionary::Object::Tablespace), m_facade(&f)
|
|
{
|
|
}
|
|
|
|
NdbTablespaceImpl::~NdbTablespaceImpl(){
|
|
}
|
|
|
|
void
|
|
NdbTablespaceImpl::assign(const NdbTablespaceImpl& org)
|
|
{
|
|
m_id = org.m_id;
|
|
m_version = org.m_version;
|
|
m_status = org.m_status;
|
|
m_type = org.m_type;
|
|
|
|
m_name.assign(org.m_name);
|
|
m_grow_spec = org.m_grow_spec;
|
|
m_extent_size = org.m_extent_size;
|
|
m_undo_free_words = org.m_undo_free_words;
|
|
m_logfile_group_id = org.m_logfile_group_id;
|
|
m_logfile_group_version = org.m_logfile_group_version;
|
|
m_logfile_group_name.assign(org.m_logfile_group_name);
|
|
m_undo_free_words = org.m_undo_free_words;
|
|
}
|
|
|
|
NdbLogfileGroupImpl::NdbLogfileGroupImpl() :
|
|
NdbDictionary::LogfileGroup(* this),
|
|
NdbFilegroupImpl(NdbDictionary::Object::LogfileGroup), m_facade(this)
|
|
{
|
|
}
|
|
|
|
NdbLogfileGroupImpl::NdbLogfileGroupImpl(NdbDictionary::LogfileGroup & f) :
|
|
NdbDictionary::LogfileGroup(* this),
|
|
NdbFilegroupImpl(NdbDictionary::Object::LogfileGroup), m_facade(&f)
|
|
{
|
|
}
|
|
|
|
NdbLogfileGroupImpl::~NdbLogfileGroupImpl(){
|
|
}
|
|
|
|
void
|
|
NdbLogfileGroupImpl::assign(const NdbLogfileGroupImpl& org)
|
|
{
|
|
m_id = org.m_id;
|
|
m_version = org.m_version;
|
|
m_status = org.m_status;
|
|
m_type = org.m_type;
|
|
|
|
m_name.assign(org.m_name);
|
|
m_grow_spec = org.m_grow_spec;
|
|
m_extent_size = org.m_extent_size;
|
|
m_undo_free_words = org.m_undo_free_words;
|
|
m_logfile_group_id = org.m_logfile_group_id;
|
|
m_logfile_group_version = org.m_logfile_group_version;
|
|
m_logfile_group_name.assign(org.m_logfile_group_name);
|
|
m_undo_free_words = org.m_undo_free_words;
|
|
}
|
|
|
|
NdbFileImpl::NdbFileImpl(NdbDictionary::Object::Type t)
|
|
: NdbDictObjectImpl(t)
|
|
{
|
|
m_size = 0;
|
|
m_free = 0;
|
|
m_filegroup_id = ~0;
|
|
m_filegroup_version = ~0;
|
|
}
|
|
|
|
NdbDatafileImpl::NdbDatafileImpl() :
|
|
NdbDictionary::Datafile(* this),
|
|
NdbFileImpl(NdbDictionary::Object::Datafile), m_facade(this)
|
|
{
|
|
}
|
|
|
|
NdbDatafileImpl::NdbDatafileImpl(NdbDictionary::Datafile & f) :
|
|
NdbDictionary::Datafile(* this),
|
|
NdbFileImpl(NdbDictionary::Object::Datafile), m_facade(&f)
|
|
{
|
|
}
|
|
|
|
NdbDatafileImpl::~NdbDatafileImpl(){
|
|
}
|
|
|
|
void
|
|
NdbDatafileImpl::assign(const NdbDatafileImpl& org)
|
|
{
|
|
m_id = org.m_id;
|
|
m_version = org.m_version;
|
|
m_status = org.m_status;
|
|
m_type = org.m_type;
|
|
|
|
m_size = org.m_size;
|
|
m_free = org.m_free;
|
|
m_filegroup_id = org.m_filegroup_id;
|
|
m_filegroup_version = org.m_filegroup_version;
|
|
m_path.assign(org.m_path);
|
|
m_filegroup_name.assign(org.m_filegroup_name);
|
|
}
|
|
|
|
NdbUndofileImpl::NdbUndofileImpl() :
|
|
NdbDictionary::Undofile(* this),
|
|
NdbFileImpl(NdbDictionary::Object::Undofile), m_facade(this)
|
|
{
|
|
}
|
|
|
|
NdbUndofileImpl::NdbUndofileImpl(NdbDictionary::Undofile & f) :
|
|
NdbDictionary::Undofile(* this),
|
|
NdbFileImpl(NdbDictionary::Object::Undofile), m_facade(&f)
|
|
{
|
|
}
|
|
|
|
NdbUndofileImpl::~NdbUndofileImpl(){
|
|
}
|
|
|
|
void
|
|
NdbUndofileImpl::assign(const NdbUndofileImpl& org)
|
|
{
|
|
m_id = org.m_id;
|
|
m_version = org.m_version;
|
|
m_status = org.m_status;
|
|
m_type = org.m_type;
|
|
|
|
m_size = org.m_size;
|
|
m_free = org.m_free;
|
|
m_filegroup_id = org.m_filegroup_id;
|
|
m_filegroup_version = org.m_filegroup_version;
|
|
m_path.assign(org.m_path);
|
|
m_filegroup_name.assign(org.m_filegroup_name);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createDatafile(const NdbDatafileImpl & file, bool force){
|
|
DBUG_ENTER("NdbDictionaryImpl::createDatafile");
|
|
NdbFilegroupImpl tmp(NdbDictionary::Object::Tablespace);
|
|
if(file.m_filegroup_version != ~(Uint32)0){
|
|
tmp.m_id = file.m_filegroup_id;
|
|
tmp.m_version = file.m_filegroup_version;
|
|
DBUG_RETURN(m_receiver.create_file(file, tmp));
|
|
}
|
|
|
|
|
|
if(m_receiver.get_filegroup(tmp, NdbDictionary::Object::Tablespace,
|
|
file.m_filegroup_name.c_str()) == 0){
|
|
DBUG_RETURN(m_receiver.create_file(file, tmp, force));
|
|
}
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropDatafile(const NdbDatafileImpl & file){
|
|
return m_receiver.drop_file(file);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createUndofile(const NdbUndofileImpl & file, bool force){
|
|
DBUG_ENTER("NdbDictionaryImpl::createUndofile");
|
|
NdbFilegroupImpl tmp(NdbDictionary::Object::LogfileGroup);
|
|
if(file.m_filegroup_version != ~(Uint32)0){
|
|
tmp.m_id = file.m_filegroup_id;
|
|
tmp.m_version = file.m_filegroup_version;
|
|
DBUG_RETURN(m_receiver.create_file(file, tmp));
|
|
}
|
|
|
|
|
|
if(m_receiver.get_filegroup(tmp, NdbDictionary::Object::LogfileGroup,
|
|
file.m_filegroup_name.c_str()) == 0){
|
|
DBUG_RETURN(m_receiver.create_file(file, tmp, force));
|
|
}
|
|
DBUG_PRINT("info", ("Failed to find filegroup"));
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropUndofile(const NdbUndofileImpl & file){
|
|
return m_receiver.drop_file(file);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createTablespace(const NdbTablespaceImpl & fg){
|
|
return m_receiver.create_filegroup(fg);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropTablespace(const NdbTablespaceImpl & fg){
|
|
return m_receiver.drop_filegroup(fg);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::createLogfileGroup(const NdbLogfileGroupImpl & fg){
|
|
return m_receiver.create_filegroup(fg);
|
|
}
|
|
|
|
int
|
|
NdbDictionaryImpl::dropLogfileGroup(const NdbLogfileGroupImpl & fg){
|
|
return m_receiver.drop_filegroup(fg);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::create_file(const NdbFileImpl & file,
|
|
const NdbFilegroupImpl & group,
|
|
bool overwrite){
|
|
DBUG_ENTER("NdbDictInterface::create_file");
|
|
UtilBufferWriter w(m_buffer);
|
|
DictFilegroupInfo::File f; f.init();
|
|
snprintf(f.FileName, sizeof(f.FileName), file.m_path.c_str());
|
|
f.FileType = file.m_type;
|
|
f.FilegroupId = group.m_id;
|
|
f.FilegroupVersion = group.m_version;
|
|
f.FileSizeHi = (file.m_size >> 32);
|
|
f.FileSizeLo = (file.m_size & 0xFFFFFFFF);
|
|
|
|
SimpleProperties::UnpackStatus s;
|
|
s = SimpleProperties::pack(w,
|
|
&f,
|
|
DictFilegroupInfo::FileMapping,
|
|
DictFilegroupInfo::FileMappingSize, true);
|
|
|
|
if(s != SimpleProperties::Eof){
|
|
abort();
|
|
}
|
|
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_CREATE_FILE_REQ;
|
|
tSignal.theLength = CreateFileReq::SignalLength;
|
|
|
|
CreateFileReq* req = CAST_PTR(CreateFileReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->objType = file.m_type;
|
|
req->requestInfo = 0;
|
|
if (overwrite)
|
|
req->requestInfo |= CreateFileReq::ForceCreateFile;
|
|
|
|
LinearSectionPtr ptr[3];
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz = m_buffer.length() / 4;
|
|
|
|
int err[] = { CreateFileRef::Busy, CreateFileRef::NotMaster, 0};
|
|
/*
|
|
Send signal without time-out since creating files can take a very long
|
|
time if the file is very big.
|
|
*/
|
|
DBUG_RETURN(dictSignal(&tSignal, ptr, 1,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
-1, 100,
|
|
err));
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_FILE_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_FILE_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const CreateFileRef* ref =
|
|
CAST_CONSTPTR(CreateFileRef, signal->getDataPtr());
|
|
m_error.code = ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::drop_file(const NdbFileImpl & file){
|
|
DBUG_ENTER("NdbDictInterface::drop_file");
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_DROP_FILE_REQ;
|
|
tSignal.theLength = DropFileReq::SignalLength;
|
|
|
|
DropFileReq* req = CAST_PTR(DropFileReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->file_id = file.m_id;
|
|
req->file_version = file.m_version;
|
|
|
|
int err[] = { DropFileRef::Busy, DropFileRef::NotMaster, 0};
|
|
DBUG_RETURN(dictSignal(&tSignal, 0, 0,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
err));
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_FILE_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_FILE_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const DropFileRef* ref =
|
|
CAST_CONSTPTR(DropFileRef, signal->getDataPtr());
|
|
m_error.code = ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::create_filegroup(const NdbFilegroupImpl & group){
|
|
DBUG_ENTER("NdbDictInterface::create_filegroup");
|
|
UtilBufferWriter w(m_buffer);
|
|
DictFilegroupInfo::Filegroup fg; fg.init();
|
|
snprintf(fg.FilegroupName, sizeof(fg.FilegroupName), group.m_name.c_str());
|
|
switch(group.m_type){
|
|
case NdbDictionary::Object::Tablespace:
|
|
{
|
|
fg.FilegroupType = DictTabInfo::Tablespace;
|
|
//fg.TS_DataGrow = group.m_grow_spec;
|
|
fg.TS_ExtentSize = group.m_extent_size;
|
|
|
|
if(group.m_logfile_group_version != ~(Uint32)0)
|
|
{
|
|
fg.TS_LogfileGroupId = group.m_logfile_group_id;
|
|
fg.TS_LogfileGroupVersion = group.m_logfile_group_version;
|
|
}
|
|
else
|
|
{
|
|
NdbLogfileGroupImpl tmp;
|
|
if(get_filegroup(tmp, NdbDictionary::Object::LogfileGroup,
|
|
group.m_logfile_group_name.c_str()) == 0)
|
|
{
|
|
fg.TS_LogfileGroupId = tmp.m_id;
|
|
fg.TS_LogfileGroupVersion = tmp.m_version;
|
|
}
|
|
else // error set by get filegroup
|
|
{
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case NdbDictionary::Object::LogfileGroup:
|
|
fg.LF_UndoBufferSize = group.m_undo_buffer_size;
|
|
fg.FilegroupType = DictTabInfo::LogfileGroup;
|
|
//fg.LF_UndoGrow = group.m_grow_spec;
|
|
break;
|
|
default:
|
|
abort();
|
|
DBUG_RETURN(-1);
|
|
};
|
|
|
|
SimpleProperties::UnpackStatus s;
|
|
s = SimpleProperties::pack(w,
|
|
&fg,
|
|
DictFilegroupInfo::Mapping,
|
|
DictFilegroupInfo::MappingSize, true);
|
|
|
|
if(s != SimpleProperties::Eof){
|
|
abort();
|
|
}
|
|
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_CREATE_FILEGROUP_REQ;
|
|
tSignal.theLength = CreateFilegroupReq::SignalLength;
|
|
|
|
CreateFilegroupReq* req =
|
|
CAST_PTR(CreateFilegroupReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->objType = fg.FilegroupType;
|
|
|
|
LinearSectionPtr ptr[3];
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
ptr[0].sz = m_buffer.length() / 4;
|
|
|
|
int err[] = { CreateFilegroupRef::Busy, CreateFilegroupRef::NotMaster, 0};
|
|
DBUG_RETURN(dictSignal(&tSignal, ptr, 1,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
err));
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_FILEGROUP_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execCREATE_FILEGROUP_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const CreateFilegroupRef* ref =
|
|
CAST_CONSTPTR(CreateFilegroupRef, signal->getDataPtr());
|
|
m_error.code = ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::drop_filegroup(const NdbFilegroupImpl & group){
|
|
DBUG_ENTER("NdbDictInterface::drop_filegroup");
|
|
NdbApiSignal tSignal(m_reference);
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_DROP_FILEGROUP_REQ;
|
|
tSignal.theLength = DropFilegroupReq::SignalLength;
|
|
|
|
DropFilegroupReq* req = CAST_PTR(DropFilegroupReq, tSignal.getDataPtrSend());
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->filegroup_id = group.m_id;
|
|
req->filegroup_version = group.m_version;
|
|
|
|
int err[] = { DropFilegroupRef::Busy, DropFilegroupRef::NotMaster, 0};
|
|
DBUG_RETURN(dictSignal(&tSignal, 0, 0,
|
|
0, // master
|
|
WAIT_CREATE_INDX_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100,
|
|
err));
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_FILEGROUP_CONF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
void
|
|
NdbDictInterface::execDROP_FILEGROUP_REF(NdbApiSignal * signal,
|
|
LinearSectionPtr ptr[3])
|
|
{
|
|
const DropFilegroupRef* ref =
|
|
CAST_CONSTPTR(DropFilegroupRef, signal->getDataPtr());
|
|
m_error.code = ref->errorCode;
|
|
m_masterNodeId = ref->masterNodeId;
|
|
m_waiter.signal(NO_WAIT);
|
|
}
|
|
|
|
|
|
int
|
|
NdbDictInterface::get_filegroup(NdbFilegroupImpl & dst,
|
|
NdbDictionary::Object::Type type,
|
|
const char * name){
|
|
DBUG_ENTER("NdbDictInterface::get_filegroup");
|
|
NdbApiSignal tSignal(m_reference);
|
|
GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
|
|
|
|
size_t strLen = strlen(name) + 1;
|
|
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestType =
|
|
GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
|
|
req->tableNameLen = strLen;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_GET_TABINFOREQ;
|
|
tSignal.theLength = GetTabInfoReq::SignalLength;
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p = (Uint32*)name;
|
|
ptr[0].sz = (strLen + 3)/4;
|
|
|
|
#ifndef IGNORE_VALGRIND_WARNINGS
|
|
if (strLen & 3)
|
|
{
|
|
Uint32 pad = 0;
|
|
m_buffer.clear();
|
|
m_buffer.append(name, strLen);
|
|
m_buffer.append(&pad, 4);
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
}
|
|
#endif
|
|
|
|
int r = dictSignal(&tSignal, ptr, 1,
|
|
-1, // any node
|
|
WAIT_GET_TAB_INFO_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100);
|
|
if (r)
|
|
{
|
|
dst.m_id = -1;
|
|
dst.m_version = ~0;
|
|
|
|
DBUG_PRINT("info", ("get_filegroup failed dictSignal"));
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
m_error.code = parseFilegroupInfo(dst,
|
|
(Uint32*)m_buffer.get_data(),
|
|
m_buffer.length() / 4);
|
|
|
|
if(m_error.code)
|
|
{
|
|
DBUG_PRINT("info", ("get_filegroup failed parseFilegroupInfo %d",
|
|
m_error.code));
|
|
DBUG_RETURN(m_error.code);
|
|
}
|
|
|
|
if(dst.m_type == NdbDictionary::Object::Tablespace)
|
|
{
|
|
NdbDictionary::LogfileGroup tmp;
|
|
get_filegroup(NdbLogfileGroupImpl::getImpl(tmp),
|
|
NdbDictionary::Object::LogfileGroup,
|
|
dst.m_logfile_group_id);
|
|
dst.m_logfile_group_name.assign(tmp.getName());
|
|
}
|
|
|
|
if(dst.m_type == type)
|
|
{
|
|
DBUG_RETURN(0);
|
|
}
|
|
DBUG_PRINT("info", ("get_filegroup failed no such filegroup"));
|
|
DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::parseFilegroupInfo(NdbFilegroupImpl &dst,
|
|
const Uint32 * data, Uint32 len)
|
|
|
|
{
|
|
SimplePropertiesLinearReader it(data, len);
|
|
|
|
SimpleProperties::UnpackStatus status;
|
|
DictFilegroupInfo::Filegroup fg; fg.init();
|
|
status = SimpleProperties::unpack(it, &fg,
|
|
DictFilegroupInfo::Mapping,
|
|
DictFilegroupInfo::MappingSize,
|
|
true, true);
|
|
|
|
if(status != SimpleProperties::Eof){
|
|
return CreateFilegroupRef::InvalidFormat;
|
|
}
|
|
|
|
dst.m_id = fg.FilegroupId;
|
|
dst.m_version = fg.FilegroupVersion;
|
|
dst.m_type = (NdbDictionary::Object::Type)fg.FilegroupType;
|
|
dst.m_status = NdbDictionary::Object::Retrieved;
|
|
|
|
dst.m_name.assign(fg.FilegroupName);
|
|
dst.m_extent_size = fg.TS_ExtentSize;
|
|
dst.m_undo_buffer_size = fg.LF_UndoBufferSize;
|
|
dst.m_logfile_group_id = fg.TS_LogfileGroupId;
|
|
dst.m_logfile_group_version = fg.TS_LogfileGroupVersion;
|
|
dst.m_undo_free_words= ((Uint64)fg.LF_UndoFreeWordsHi << 32)
|
|
| (fg.LF_UndoFreeWordsLo);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::get_filegroup(NdbFilegroupImpl & dst,
|
|
NdbDictionary::Object::Type type,
|
|
Uint32 id){
|
|
DBUG_ENTER("NdbDictInterface::get_filegroup");
|
|
NdbApiSignal tSignal(m_reference);
|
|
GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
|
|
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestType =
|
|
GetTabInfoReq::RequestById | GetTabInfoReq::LongSignalConf;
|
|
req->tableId = id;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_GET_TABINFOREQ;
|
|
tSignal.theLength = GetTabInfoReq::SignalLength;
|
|
|
|
int r = dictSignal(&tSignal, NULL, 1,
|
|
-1, // any node
|
|
WAIT_GET_TAB_INFO_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100);
|
|
if (r)
|
|
{
|
|
DBUG_PRINT("info", ("get_filegroup failed dictSignal"));
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
m_error.code = parseFilegroupInfo(dst,
|
|
(Uint32*)m_buffer.get_data(),
|
|
m_buffer.length() / 4);
|
|
|
|
if(m_error.code)
|
|
{
|
|
DBUG_PRINT("info", ("get_filegroup failed parseFilegroupInfo %d",
|
|
m_error.code));
|
|
DBUG_RETURN(m_error.code);
|
|
}
|
|
|
|
if(dst.m_type == type)
|
|
{
|
|
DBUG_RETURN(0);
|
|
}
|
|
DBUG_PRINT("info", ("get_filegroup failed no such filegroup"));
|
|
DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::get_file(NdbFileImpl & dst,
|
|
NdbDictionary::Object::Type type,
|
|
int node,
|
|
const char * name){
|
|
DBUG_ENTER("NdbDictInterface::get_file");
|
|
NdbApiSignal tSignal(m_reference);
|
|
GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
|
|
|
|
size_t strLen = strlen(name) + 1;
|
|
|
|
req->senderRef = m_reference;
|
|
req->senderData = 0;
|
|
req->requestType =
|
|
GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
|
|
req->tableNameLen = strLen;
|
|
tSignal.theReceiversBlockNumber = DBDICT;
|
|
tSignal.theVerId_signalNumber = GSN_GET_TABINFOREQ;
|
|
tSignal.theLength = GetTabInfoReq::SignalLength;
|
|
|
|
LinearSectionPtr ptr[1];
|
|
ptr[0].p = (Uint32*)name;
|
|
ptr[0].sz = (strLen + 3)/4;
|
|
|
|
#ifndef IGNORE_VALGRIND_WARNINGS
|
|
if (strLen & 3)
|
|
{
|
|
Uint32 pad = 0;
|
|
m_buffer.clear();
|
|
m_buffer.append(name, strLen);
|
|
m_buffer.append(&pad, 4);
|
|
ptr[0].p = (Uint32*)m_buffer.get_data();
|
|
}
|
|
#endif
|
|
|
|
int r = dictSignal(&tSignal, ptr, 1,
|
|
node,
|
|
WAIT_GET_TAB_INFO_REQ,
|
|
DICT_WAITFOR_TIMEOUT, 100);
|
|
if (r)
|
|
{
|
|
DBUG_PRINT("info", ("get_file failed dictSignal"));
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
m_error.code = parseFileInfo(dst,
|
|
(Uint32*)m_buffer.get_data(),
|
|
m_buffer.length() / 4);
|
|
|
|
if(m_error.code)
|
|
{
|
|
DBUG_PRINT("info", ("get_file failed parseFileInfo %d",
|
|
m_error.code));
|
|
DBUG_RETURN(m_error.code);
|
|
}
|
|
|
|
if(dst.m_type == NdbDictionary::Object::Undofile)
|
|
{
|
|
NdbDictionary::LogfileGroup tmp;
|
|
get_filegroup(NdbLogfileGroupImpl::getImpl(tmp),
|
|
NdbDictionary::Object::LogfileGroup,
|
|
dst.m_filegroup_id);
|
|
dst.m_filegroup_name.assign(tmp.getName());
|
|
}
|
|
else if(dst.m_type == NdbDictionary::Object::Datafile)
|
|
{
|
|
NdbDictionary::Tablespace tmp;
|
|
get_filegroup(NdbTablespaceImpl::getImpl(tmp),
|
|
NdbDictionary::Object::Tablespace,
|
|
dst.m_filegroup_id);
|
|
dst.m_filegroup_name.assign(tmp.getName());
|
|
dst.m_free *= tmp.getExtentSize();
|
|
}
|
|
else
|
|
dst.m_filegroup_name.assign("Not Yet Implemented");
|
|
|
|
if(dst.m_type == type)
|
|
{
|
|
DBUG_RETURN(0);
|
|
}
|
|
DBUG_PRINT("info", ("get_file failed no such file"));
|
|
DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
|
|
}
|
|
|
|
int
|
|
NdbDictInterface::parseFileInfo(NdbFileImpl &dst,
|
|
const Uint32 * data, Uint32 len)
|
|
{
|
|
SimplePropertiesLinearReader it(data, len);
|
|
|
|
SimpleProperties::UnpackStatus status;
|
|
DictFilegroupInfo::File f; f.init();
|
|
status = SimpleProperties::unpack(it, &f,
|
|
DictFilegroupInfo::FileMapping,
|
|
DictFilegroupInfo::FileMappingSize,
|
|
true, true);
|
|
|
|
if(status != SimpleProperties::Eof){
|
|
return CreateFilegroupRef::InvalidFormat;
|
|
}
|
|
|
|
dst.m_type= (NdbDictionary::Object::Type)f.FileType;
|
|
dst.m_id= f.FileId;
|
|
dst.m_version = f.FileVersion;
|
|
|
|
dst.m_size= ((Uint64)f.FileSizeHi << 32) | (f.FileSizeLo);
|
|
dst.m_path.assign(f.FileName);
|
|
|
|
dst.m_filegroup_id= f.FilegroupId;
|
|
dst.m_filegroup_version= f.FilegroupVersion;
|
|
dst.m_free= f.FileFreeExtents;
|
|
return 0;
|
|
}
|
|
|
|
template class Vector<int>;
|
|
template class Vector<Uint16>;
|
|
template class Vector<Uint32>;
|
|
template class Vector<Vector<Uint32> >;
|
|
template class Vector<NdbTableImpl*>;
|
|
template class Vector<NdbColumnImpl*>;
|
|
|
|
const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_MEMORY = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::ROW_COUNT = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::COMMIT_COUNT = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::ROW_SIZE = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::RANGE_NO = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::DISK_REF = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::RECORDS_IN_RANGE = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::ROWID = 0;
|
|
const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI = 0;
|