1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "API.hpp"
26 #include <NdbOut.hpp>
27 #include <SimpleProperties.hpp>
28 #include <Bitmask.hpp>
29 #include <AttributeList.hpp>
30 #include <AttributeHeader.hpp>
31 #include <my_sys.h>
32 #include <NdbEnv.h>
33 #include <NdbMem.h>
34 #include <util/version.h>
35 #include <NdbSleep.h>
36 #include <signaldata/IndexStatSignal.hpp>
37 
38 #include <signaldata/GetTabInfo.hpp>
39 #include <signaldata/DictTabInfo.hpp>
40 #include <signaldata/CreateTable.hpp>
41 #include <signaldata/CreateIndx.hpp>
42 #include <signaldata/CreateEvnt.hpp>
43 #include <signaldata/SumaImpl.hpp>
44 #include <signaldata/DropTable.hpp>
45 #include <signaldata/AlterTable.hpp>
46 #include <signaldata/DropIndx.hpp>
47 #include <signaldata/ListTables.hpp>
48 #include <signaldata/DropFilegroup.hpp>
49 #include <signaldata/CreateFilegroup.hpp>
50 #include <signaldata/WaitGCP.hpp>
51 #include <signaldata/SchemaTrans.hpp>
52 #include <signaldata/CreateHashMap.hpp>
53 #include <signaldata/ApiRegSignalData.hpp>
54 #include <signaldata/NodeFailRep.hpp>
55 #include <signaldata/CreateFK.hpp>
56 #include <signaldata/DropFK.hpp>
57 
58 #define DEBUG_PRINT 0
59 #define INCOMPATIBLE_VERSION -2
60 
61 #define DICT_WAITFOR_TIMEOUT (7*24*60*60*1000)
62 
63 #define ERR_RETURN(a,b) \
64 {\
65    DBUG_PRINT("exit", ("error %d  return %d", (a).code, b));\
66    DBUG_RETURN(b);\
67 }
68 
69 int ndb_dictionary_is_mysqld = 0;
70 
71 bool
is_ndb_blob_table(const char * name,Uint32 * ptab_id,Uint32 * pcol_no)72 is_ndb_blob_table(const char* name, Uint32* ptab_id, Uint32* pcol_no)
73 {
74   return DictTabInfo::isBlobTableName(name, ptab_id, pcol_no);
75 }
76 
77 bool
is_ndb_blob_table(const NdbTableImpl * t)78 is_ndb_blob_table(const NdbTableImpl* t)
79 {
80   return is_ndb_blob_table(t->m_internalName.c_str());
81 }
82 
83 bool
ignore_broken_blob_tables()84 ignore_broken_blob_tables()
85 {
86   /* To be able to fix broken blob tables, we must be able
87    * to ignore them when getting the table description
88    */
89   char envBuf[10];
90   const char* v = NdbEnv_GetEnv("NDB_FORCE_IGNORE_BROKEN_BLOB",
91                                 envBuf,
92                                 10);
93   return (v != NULL && *v != 0 && *v != '0' && *v != 'n' && *v != 'N');
94 }
95 
96 //#define EVENT_DEBUG
97 
98 /**
99  * Column
100  */
NdbColumnImpl()101 NdbColumnImpl::NdbColumnImpl()
102   : NdbDictionary::Column(* this), m_attrId(-1), m_facade(this)
103 {
104   init();
105 }
106 
NdbColumnImpl(NdbDictionary::Column & f)107 NdbColumnImpl::NdbColumnImpl(NdbDictionary::Column & f)
108   : NdbDictionary::Column(* this), m_attrId(-1), m_facade(&f)
109 {
110   init();
111 }
112 
113 NdbColumnImpl&
operator =(const NdbColumnImpl & col)114 NdbColumnImpl::operator=(const NdbColumnImpl& col)
115 {
116   m_attrId = col.m_attrId;
117   m_name = col.m_name;
118   m_type = col.m_type;
119   m_precision = col.m_precision;
120   m_cs = col.m_cs;
121   m_scale = col.m_scale;
122   m_length = col.m_length;
123   m_pk = col.m_pk;
124   m_distributionKey = col.m_distributionKey;
125   m_nullable = col.m_nullable;
126   m_autoIncrement = col.m_autoIncrement;
127   m_autoIncrementInitialValue = col.m_autoIncrementInitialValue;
128   m_defaultValue.assign(col.m_defaultValue);
129   m_attrSize = col.m_attrSize;
130   m_arraySize = col.m_arraySize;
131   m_arrayType = col.m_arrayType;
132   m_storageType = col.m_storageType;
133   m_blobVersion = col.m_blobVersion;
134   m_dynamic = col.m_dynamic;
135   m_indexSourced = col.m_indexSourced;
136   m_keyInfoPos = col.m_keyInfoPos;
137   if (col.m_blobTable == NULL)
138     m_blobTable = NULL;
139   else {
140     if (m_blobTable == NULL)
141       m_blobTable = new NdbTableImpl();
142     m_blobTable->assign(*col.m_blobTable);
143   }
144   m_column_no = col.m_column_no;
145   // Do not copy m_facade !!
146 
147   return *this;
148 }
149 
150 void
init(Type t)151 NdbColumnImpl::init(Type t)
152 {
153   // do not use default_charset_info as it may not be initialized yet
154   // use binary collation until NDB tests can handle charsets
155   CHARSET_INFO* default_cs = &my_charset_bin;
156   m_blobVersion = 0;
157   m_type = t;
158   switch (m_type) {
159   case Tinyint:
160   case Tinyunsigned:
161   case Smallint:
162   case Smallunsigned:
163   case Mediumint:
164   case Mediumunsigned:
165   case Int:
166   case Unsigned:
167   case Bigint:
168   case Bigunsigned:
169   case Float:
170   case Double:
171     m_precision = 0;
172     m_scale = 0;
173     m_length = 1;
174     m_cs = NULL;
175     m_arrayType = NDB_ARRAYTYPE_FIXED;
176     break;
177   case Olddecimal:
178   case Olddecimalunsigned:
179   case Decimal:
180   case Decimalunsigned:
181     m_precision = 10;
182     m_scale = 0;
183     m_length = 1;
184     m_cs = NULL;
185     m_arrayType = NDB_ARRAYTYPE_FIXED;
186     break;
187   case Char:
188     m_precision = 0;
189     m_scale = 0;
190     m_length = 1;
191     m_cs = default_cs;
192     m_arrayType = NDB_ARRAYTYPE_FIXED;
193     break;
194   case Varchar:
195     m_precision = 0;
196     m_scale = 0;
197     m_length = 1;
198     m_cs = default_cs;
199     m_arrayType = NDB_ARRAYTYPE_SHORT_VAR;
200     break;
201   case Binary:
202     m_precision = 0;
203     m_scale = 0;
204     m_length = 1;
205     m_cs = NULL;
206     m_arrayType = NDB_ARRAYTYPE_FIXED;
207     break;
208   case Varbinary:
209     m_precision = 0;
210     m_scale = 0;
211     m_length = 1;
212     m_cs = NULL;
213     m_arrayType = NDB_ARRAYTYPE_SHORT_VAR;
214     break;
215   case Datetime:
216   case Date:
217     m_precision = 0;
218     m_scale = 0;
219     m_length = 1;
220     m_cs = NULL;
221     m_arrayType = NDB_ARRAYTYPE_FIXED;
222     break;
223   case Blob:
224   case Text:
225     m_precision = 256;
226     m_scale = 8000;
227     m_length = 0; // default no striping
228     m_cs = m_type == Blob ? NULL : default_cs;
229     m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
230     m_blobVersion = NDB_BLOB_V2;
231 #ifdef VM_TRACE
232 #ifdef NDB_USE_GET_ENV
233     if (NdbEnv_GetEnv("NDB_DEFAULT_BLOB_V1", (char *)0, 0)) {
234       m_length = 4;
235       m_arrayType = NDB_ARRAYTYPE_FIXED;
236       m_blobVersion = NDB_BLOB_V1;
237     }
238 #endif
239 #endif
240     break;
241   case Time:
242   case Year:
243   case Timestamp:
244     m_precision = 0;
245     m_scale = 0;
246     m_length = 1;
247     m_cs = NULL;
248     m_arrayType = NDB_ARRAYTYPE_FIXED;
249     break;
250   case Bit:
251     m_precision = 0;
252     m_scale = 0;
253     m_length = 1;
254     m_cs = NULL;
255     m_arrayType = NDB_ARRAYTYPE_FIXED;
256     break;
257   case Longvarchar:
258     m_precision = 0;
259     m_scale = 0;
260     m_length = 1; // legal
261     m_cs = default_cs;
262     m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
263     break;
264   case Longvarbinary:
265     m_precision = 0;
266     m_scale = 0;
267     m_length = 1; // legal
268     m_cs = NULL;
269     m_arrayType = NDB_ARRAYTYPE_MEDIUM_VAR;
270     break;
271   case Time2:
272   case Datetime2:
273   case Timestamp2:
274     m_precision = 0;
275     m_scale = 0;
276     m_length = 1;
277     m_cs = NULL;
278     m_arrayType = NDB_ARRAYTYPE_FIXED;
279     break;
280   default:
281   case Undefined:
282     assert(false);
283     break;
284   }
285   m_pk = false;
286   m_nullable = false;
287   m_distributionKey = false;
288   m_keyInfoPos = 0;
289   // next 2 are set at run time
290   m_attrSize = 0;
291   m_arraySize = 0;
292   m_autoIncrement = false;
293   m_autoIncrementInitialValue = 1;
294   m_blobTable = NULL;
295   m_storageType = NDB_STORAGETYPE_MEMORY;
296   m_dynamic = false;
297   m_indexSourced= false;
298 #ifdef VM_TRACE
299 #ifdef NDB_USE_GET_ENV
300   if(NdbEnv_GetEnv("NDB_DEFAULT_DISK", (char *)0, 0))
301     m_storageType = NDB_STORAGETYPE_DISK;
302 #endif
303 #endif
304 }
305 
~NdbColumnImpl()306 NdbColumnImpl::~NdbColumnImpl()
307 {
308   if (m_blobTable != NULL)
309     delete m_blobTable;
310   m_blobTable = NULL;
311 }
312 
313 bool
equal(const NdbColumnImpl & col) const314 NdbColumnImpl::equal(const NdbColumnImpl& col) const
315 {
316   DBUG_ENTER("NdbColumnImpl::equal");
317   DBUG_PRINT("info", ("this: %p  &col: %p", this, &col));
318   /* New member comparisons added here should also be
319    * handled in the BackupRestore::column_compatible_check()
320    * member of tools/restore/consumer_restore.cpp
321    */
322   if(strcmp(m_name.c_str(), col.m_name.c_str()) != 0){
323     DBUG_RETURN(false);
324   }
325   if(m_type != col.m_type){
326     DBUG_RETURN(false);
327   }
328   if(m_pk != col.m_pk){
329     DBUG_RETURN(false);
330   }
331   if(m_nullable != col.m_nullable){
332     DBUG_RETURN(false);
333   }
334   if (m_pk) {
335     if (m_distributionKey != col.m_distributionKey) {
336       DBUG_RETURN(false);
337     }
338   }
339   if (m_precision != col.m_precision ||
340       m_scale != col.m_scale ||
341       m_length != col.m_length ||
342       m_cs != col.m_cs) {
343     DBUG_RETURN(false);
344   }
345   if (m_autoIncrement != col.m_autoIncrement){
346     DBUG_RETURN(false);
347   }
348   if (m_defaultValue.length() != col.m_defaultValue.length())
349     DBUG_RETURN(false);
350 
351   if(memcmp(m_defaultValue.get_data(), col.m_defaultValue.get_data(), m_defaultValue.length()) != 0){
352     DBUG_RETURN(false);
353   }
354 
355   if (m_arrayType != col.m_arrayType || m_storageType != col.m_storageType){
356     DBUG_RETURN(false);
357   }
358   if (m_blobVersion != col.m_blobVersion) {
359     DBUG_RETURN(false);
360   }
361   if(m_dynamic != col.m_dynamic){
362     DBUG_RETURN(false);
363   }
364 
365   DBUG_RETURN(true);
366 }
367 
368 void
create_pseudo_columns()369 NdbColumnImpl::create_pseudo_columns()
370 {
371   NdbDictionary::Column::FRAGMENT=
372     NdbColumnImpl::create_pseudo("NDB$FRAGMENT");
373   NdbDictionary::Column::FRAGMENT_FIXED_MEMORY=
374     NdbColumnImpl::create_pseudo("NDB$FRAGMENT_FIXED_MEMORY");
375   NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY=
376     NdbColumnImpl::create_pseudo("NDB$FRAGMENT_VARSIZED_MEMORY");
377   NdbDictionary::Column::ROW_COUNT=
378     NdbColumnImpl::create_pseudo("NDB$ROW_COUNT");
379   NdbDictionary::Column::COMMIT_COUNT=
380     NdbColumnImpl::create_pseudo("NDB$COMMIT_COUNT");
381   NdbDictionary::Column::ROW_SIZE=
382     NdbColumnImpl::create_pseudo("NDB$ROW_SIZE");
383   NdbDictionary::Column::RANGE_NO=
384     NdbColumnImpl::create_pseudo("NDB$RANGE_NO");
385   NdbDictionary::Column::DISK_REF=
386     NdbColumnImpl::create_pseudo("NDB$DISK_REF");
387   NdbDictionary::Column::RECORDS_IN_RANGE=
388     NdbColumnImpl::create_pseudo("NDB$RECORDS_IN_RANGE");
389   NdbDictionary::Column::ROWID=
390     NdbColumnImpl::create_pseudo("NDB$ROWID");
391   NdbDictionary::Column::ROW_GCI=
392     NdbColumnImpl::create_pseudo("NDB$ROW_GCI");
393   NdbDictionary::Column::ROW_GCI64 =
394     NdbColumnImpl::create_pseudo("NDB$ROW_GCI64");
395   NdbDictionary::Column::ROW_AUTHOR =
396     NdbColumnImpl::create_pseudo("NDB$ROW_AUTHOR");
397   NdbDictionary::Column::ANY_VALUE=
398     NdbColumnImpl::create_pseudo("NDB$ANY_VALUE");
399   NdbDictionary::Column::COPY_ROWID=
400     NdbColumnImpl::create_pseudo("NDB$COPY_ROWID");
401   NdbDictionary::Column::OPTIMIZE=
402     NdbColumnImpl::create_pseudo("NDB$OPTIMIZE");
403   NdbDictionary::Column::FRAGMENT_EXTENT_SPACE =
404     NdbColumnImpl::create_pseudo("NDB$FRAGMENT_EXTENT_SPACE");
405   NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE =
406     NdbColumnImpl::create_pseudo("NDB$FRAGMENT_FREE_EXTENT_SPACE");
407   NdbDictionary::Column::LOCK_REF =
408     NdbColumnImpl::create_pseudo("NDB$LOCK_REF");
409   NdbDictionary::Column::OP_ID =
410     NdbColumnImpl::create_pseudo("NDB$OP_ID");
411 }
412 
413 void
destory_pseudo_columns()414 NdbColumnImpl::destory_pseudo_columns()
415 {
416   delete NdbDictionary::Column::FRAGMENT;
417   delete NdbDictionary::Column::FRAGMENT_FIXED_MEMORY;
418   delete NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY;
419   delete NdbDictionary::Column::ROW_COUNT;
420   delete NdbDictionary::Column::COMMIT_COUNT;
421   delete NdbDictionary::Column::ROW_SIZE;
422   delete NdbDictionary::Column::RANGE_NO;
423   delete NdbDictionary::Column::DISK_REF;
424   delete NdbDictionary::Column::RECORDS_IN_RANGE;
425   delete NdbDictionary::Column::ROWID;
426   delete NdbDictionary::Column::ROW_GCI;
427   delete NdbDictionary::Column::ROW_GCI64;
428   delete NdbDictionary::Column::ROW_AUTHOR;
429   delete NdbDictionary::Column::ANY_VALUE;
430   delete NdbDictionary::Column::OPTIMIZE;
431   NdbDictionary::Column::FRAGMENT= 0;
432   NdbDictionary::Column::FRAGMENT_FIXED_MEMORY= 0;
433   NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY= 0;
434   NdbDictionary::Column::ROW_COUNT= 0;
435   NdbDictionary::Column::COMMIT_COUNT= 0;
436   NdbDictionary::Column::ROW_SIZE= 0;
437   NdbDictionary::Column::RANGE_NO= 0;
438   NdbDictionary::Column::DISK_REF= 0;
439   NdbDictionary::Column::RECORDS_IN_RANGE= 0;
440   NdbDictionary::Column::ROWID= 0;
441   NdbDictionary::Column::ROW_GCI= 0;
442   NdbDictionary::Column::ROW_GCI64= 0;
443   NdbDictionary::Column::ROW_AUTHOR= 0;
444   NdbDictionary::Column::ANY_VALUE= 0;
445   NdbDictionary::Column::OPTIMIZE= 0;
446 
447   delete NdbDictionary::Column::COPY_ROWID;
448   NdbDictionary::Column::COPY_ROWID = 0;
449 
450   delete NdbDictionary::Column::FRAGMENT_EXTENT_SPACE;
451   NdbDictionary::Column::FRAGMENT_EXTENT_SPACE = 0;
452 
453   delete NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE;
454   NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE = 0;
455 
456   delete NdbDictionary::Column::LOCK_REF;
457   delete NdbDictionary::Column::OP_ID;
458   NdbDictionary::Column::LOCK_REF = 0;
459   NdbDictionary::Column::OP_ID = 0;
460 }
461 
462 NdbDictionary::Column *
create_pseudo(const char * name)463 NdbColumnImpl::create_pseudo(const char * name){
464   NdbDictionary::Column * col = new NdbDictionary::Column();
465   col->setName(name);
466   if(!strcmp(name, "NDB$FRAGMENT")){
467     col->setType(NdbDictionary::Column::Unsigned);
468     col->m_impl.m_attrId = AttributeHeader::FRAGMENT;
469     col->m_impl.m_attrSize = 4;
470     col->m_impl.m_arraySize = 1;
471   } else if(!strcmp(name, "NDB$FRAGMENT_FIXED_MEMORY")){
472     col->setType(NdbDictionary::Column::Bigunsigned);
473     col->m_impl.m_attrId = AttributeHeader::FRAGMENT_FIXED_MEMORY;
474     col->m_impl.m_attrSize = 8;
475     col->m_impl.m_arraySize = 1;
476   } else if(!strcmp(name, "NDB$FRAGMENT_VARSIZED_MEMORY")){
477     col->setType(NdbDictionary::Column::Bigunsigned);
478     col->m_impl.m_attrId = AttributeHeader::FRAGMENT_VARSIZED_MEMORY;
479     col->m_impl.m_attrSize = 8;
480     col->m_impl.m_arraySize = 1;
481   } else if(!strcmp(name, "NDB$ROW_COUNT")){
482     col->setType(NdbDictionary::Column::Bigunsigned);
483     col->m_impl.m_attrId = AttributeHeader::ROW_COUNT;
484     col->m_impl.m_attrSize = 8;
485     col->m_impl.m_arraySize = 1;
486   } else if(!strcmp(name, "NDB$COMMIT_COUNT")){
487     col->setType(NdbDictionary::Column::Bigunsigned);
488     col->m_impl.m_attrId = AttributeHeader::COMMIT_COUNT;
489     col->m_impl.m_attrSize = 8;
490     col->m_impl.m_arraySize = 1;
491   } else if(!strcmp(name, "NDB$ROW_SIZE")){
492     col->setType(NdbDictionary::Column::Unsigned);
493     col->m_impl.m_attrId = AttributeHeader::ROW_SIZE;
494     col->m_impl.m_attrSize = 4;
495     col->m_impl.m_arraySize = 1;
496   } else if(!strcmp(name, "NDB$RANGE_NO")){
497     col->setType(NdbDictionary::Column::Unsigned);
498     col->m_impl.m_attrId = AttributeHeader::RANGE_NO;
499     col->m_impl.m_attrSize = 4;
500     col->m_impl.m_arraySize = 1;
501   } else if(!strcmp(name, "NDB$DISK_REF")){
502     col->setType(NdbDictionary::Column::Bigunsigned);
503     col->m_impl.m_attrId = AttributeHeader::DISK_REF;
504     col->m_impl.m_attrSize = 8;
505     col->m_impl.m_arraySize = 1;
506   } else if(!strcmp(name, "NDB$RECORDS_IN_RANGE")){
507     col->setType(NdbDictionary::Column::Unsigned);
508     col->m_impl.m_attrId = AttributeHeader::RECORDS_IN_RANGE;
509     col->m_impl.m_attrSize = 4;
510     col->m_impl.m_arraySize = 4;
511   } else if(!strcmp(name, "NDB$ROWID")){
512     col->setType(NdbDictionary::Column::Bigunsigned);
513     col->m_impl.m_attrId = AttributeHeader::ROWID;
514     col->m_impl.m_attrSize = 4;
515     col->m_impl.m_arraySize = 2;
516   } else if(!strcmp(name, "NDB$ROW_GCI")){
517     col->setType(NdbDictionary::Column::Bigunsigned);
518     col->m_impl.m_attrId = AttributeHeader::ROW_GCI;
519     col->m_impl.m_attrSize = 8;
520     col->m_impl.m_arraySize = 1;
521     col->m_impl.m_nullable = true;
522   } else if(!strcmp(name, "NDB$ROW_GCI64")){
523     col->setType(NdbDictionary::Column::Bigunsigned);
524     col->m_impl.m_attrId = AttributeHeader::ROW_GCI64;
525     col->m_impl.m_attrSize = 8;
526     col->m_impl.m_arraySize = 1;
527     col->m_impl.m_nullable = true;
528   } else if(!strcmp(name, "NDB$ROW_AUTHOR")){
529     col->setType(NdbDictionary::Column::Unsigned);
530     col->m_impl.m_attrId = AttributeHeader::ROW_AUTHOR;
531     col->m_impl.m_attrSize = 4;
532     col->m_impl.m_arraySize = 1;
533     col->m_impl.m_nullable = true;
534   } else if(!strcmp(name, "NDB$ANY_VALUE")){
535     col->setType(NdbDictionary::Column::Unsigned);
536     col->m_impl.m_attrId = AttributeHeader::ANY_VALUE;
537     col->m_impl.m_attrSize = 4;
538     col->m_impl.m_arraySize = 1;
539   } else if(!strcmp(name, "NDB$COPY_ROWID")){
540     col->setType(NdbDictionary::Column::Bigunsigned);
541     col->m_impl.m_attrId = AttributeHeader::COPY_ROWID;
542     col->m_impl.m_attrSize = 4;
543     col->m_impl.m_arraySize = 2;
544   } else if(!strcmp(name, "NDB$OPTIMIZE")){
545     col->setType(NdbDictionary::Column::Unsigned);
546     col->m_impl.m_attrId = AttributeHeader::OPTIMIZE;
547     col->m_impl.m_attrSize = 4;
548     col->m_impl.m_arraySize = 1;
549   } else if(!strcmp(name, "NDB$FRAGMENT_EXTENT_SPACE")){
550     col->setType(NdbDictionary::Column::Bigunsigned);
551     col->m_impl.m_attrId = AttributeHeader::FRAGMENT_EXTENT_SPACE;
552     col->m_impl.m_attrSize = 4;
553     col->m_impl.m_arraySize = 2;
554   } else if(!strcmp(name, "NDB$FRAGMENT_FREE_EXTENT_SPACE")){
555     col->setType(NdbDictionary::Column::Bigunsigned);
556     col->m_impl.m_attrId = AttributeHeader::FRAGMENT_FREE_EXTENT_SPACE;
557     col->m_impl.m_attrSize = 4;
558     col->m_impl.m_arraySize = 2;
559   } else if (!strcmp(name, "NDB$LOCK_REF")){
560     col->setType(NdbDictionary::Column::Unsigned);
561     col->m_impl.m_attrId = AttributeHeader::LOCK_REF;
562     col->m_impl.m_attrSize = 4;
563     col->m_impl.m_arraySize = 3;
564   } else if (!strcmp(name, "NDB$OP_ID")){
565     col->setType(NdbDictionary::Column::Bigunsigned);
566     col->m_impl.m_attrId = AttributeHeader::OP_ID;
567     col->m_impl.m_attrSize = 8;
568     col->m_impl.m_arraySize = 1;
569   }
570   else {
571     abort();
572   }
573   col->m_impl.m_storageType = NDB_STORAGETYPE_MEMORY;
574   return col;
575 }
576 
577 /**
578  * NdbTableImpl
579  */
580 
NdbTableImpl()581 NdbTableImpl::NdbTableImpl()
582   : NdbDictionary::Table(* this),
583     NdbDictObjectImpl(NdbDictionary::Object::UserTable), m_facade(this)
584 {
585   init();
586 }
587 
NdbTableImpl(NdbDictionary::Table & f)588 NdbTableImpl::NdbTableImpl(NdbDictionary::Table & f)
589   : NdbDictionary::Table(* this),
590     NdbDictObjectImpl(NdbDictionary::Object::UserTable), m_facade(&f)
591 {
592   init();
593 }
594 
~NdbTableImpl()595 NdbTableImpl::~NdbTableImpl()
596 {
597   if (m_index != 0) {
598     delete m_index;
599     m_index = 0;
600   }
601   for (unsigned i = 0; i < m_columns.size(); i++)
602     delete m_columns[i];
603 
604   if (m_ndbrecord !=0) {
605     free(m_ndbrecord); // As it was calloc'd
606     m_ndbrecord= 0;
607   }
608 
609   if (m_pkMask != 0) {
610     free(const_cast<unsigned char *>(m_pkMask));
611     m_pkMask= 0;
612   }
613 }
614 
615 void
init()616 NdbTableImpl::init(){
617   m_id= RNIL;
618   m_version = ~0;
619   m_status = NdbDictionary::Object::Invalid;
620   m_type = NdbDictionary::Object::TypeUndefined;
621   m_primaryTableId= RNIL;
622   m_internalName.clear();
623   m_externalName.clear();
624   m_mysqlName.clear();
625   m_frm.clear();
626   m_fd.clear();
627   m_range.clear();
628   m_fragmentType= NdbDictionary::Object::HashMapPartition;
629   m_hashValueMask= 0;
630   m_hashpointerValue= 0;
631   m_linear_flag= true;
632   m_primaryTable.clear();
633   m_default_no_part_flag = 1;
634   m_logging= true;
635   m_temporary = false;
636   m_row_gci = true;
637   m_row_checksum = true;
638   m_force_var_part = false;
639   m_has_default_values = false;
640   m_kvalue= 6;
641   m_minLoadFactor= 78;
642   m_maxLoadFactor= 80;
643   m_keyLenInWords= 0;
644   m_fragmentCount= 0;
645   m_index= NULL;
646   m_indexType= NdbDictionary::Object::TypeUndefined;
647   m_noOfKeys= 0;
648   m_noOfDistributionKeys= 0;
649   m_noOfBlobs= 0;
650   m_replicaCount= 0;
651   m_noOfAutoIncColumns = 0;
652   m_ndbrecord= 0;
653   m_pkMask= 0;
654   m_min_rows = 0;
655   m_max_rows = 0;
656   m_tablespace_name.clear();
657   m_tablespace_id = RNIL;
658   m_tablespace_version = ~0;
659   m_single_user_mode = 0;
660   m_hash_map_id = RNIL;
661   m_hash_map_version = ~0;
662   m_storageType = NDB_STORAGETYPE_DEFAULT;
663   m_extra_row_gci_bits = 0;
664   m_extra_row_author_bits = 0;
665 }
666 
667 bool
equal(const NdbTableImpl & obj) const668 NdbTableImpl::equal(const NdbTableImpl& obj) const
669 {
670   DBUG_ENTER("NdbTableImpl::equal");
671   if ((m_internalName.c_str() == NULL) ||
672       (strcmp(m_internalName.c_str(), "") == 0) ||
673       (obj.m_internalName.c_str() == NULL) ||
674       (strcmp(obj.m_internalName.c_str(), "") == 0))
675   {
676     // Shallow equal
677     if(strcmp(getName(), obj.getName()) != 0)
678     {
679       DBUG_PRINT("info",("name %s != %s",getName(),obj.getName()));
680       DBUG_RETURN(false);
681     }
682   }
683   else
684   {
685     // Deep equal
686     if(strcmp(m_internalName.c_str(), obj.m_internalName.c_str()) != 0)
687     {
688       DBUG_PRINT("info",("m_internalName %s != %s",
689 			 m_internalName.c_str(),obj.m_internalName.c_str()));
690       DBUG_RETURN(false);
691     }
692   }
693   if (m_frm.length() != obj.m_frm.length() ||
694       (memcmp(m_frm.get_data(), obj.m_frm.get_data(), m_frm.length())))
695   {
696     DBUG_PRINT("info",("m_frm not equal"));
697     DBUG_RETURN(false);
698   }
699   if (!m_fd.equal(obj.m_fd))
700   {
701     DBUG_PRINT("info",("m_fd not equal"));
702     DBUG_RETURN(false);
703   }
704   if (!m_range.equal(obj.m_range))
705   {
706     DBUG_PRINT("info",("m_range not equal"));
707     DBUG_RETURN(false);
708   }
709   if(m_fragmentType != obj.m_fragmentType)
710   {
711     DBUG_PRINT("info",("m_fragmentType %d != %d",m_fragmentType,
712                         obj.m_fragmentType));
713     DBUG_RETURN(false);
714   }
715   if(m_columns.size() != obj.m_columns.size())
716   {
717     DBUG_PRINT("info",("m_columns.size %d != %d",m_columns.size(),
718                        obj.m_columns.size()));
719     DBUG_RETURN(false);
720   }
721 
722   for(unsigned i = 0; i<obj.m_columns.size(); i++)
723   {
724     if(!m_columns[i]->equal(* obj.m_columns[i]))
725     {
726       DBUG_PRINT("info",("m_columns [%d] != [%d]",i,i));
727       DBUG_RETURN(false);
728     }
729   }
730 
731   if(m_linear_flag != obj.m_linear_flag)
732   {
733     DBUG_PRINT("info",("m_linear_flag %d != %d",m_linear_flag,
734                         obj.m_linear_flag));
735     DBUG_RETURN(false);
736   }
737 
738   if(m_max_rows != obj.m_max_rows)
739   {
740     DBUG_PRINT("info",("m_max_rows %d != %d",(int32)m_max_rows,
741                        (int32)obj.m_max_rows));
742     DBUG_RETURN(false);
743   }
744 
745   if(m_default_no_part_flag != obj.m_default_no_part_flag)
746   {
747     DBUG_PRINT("info",("m_default_no_part_flag %d != %d",m_default_no_part_flag,
748                         obj.m_default_no_part_flag));
749     DBUG_RETURN(false);
750   }
751 
752   if(m_logging != obj.m_logging)
753   {
754     DBUG_PRINT("info",("m_logging %d != %d",m_logging,obj.m_logging));
755     DBUG_RETURN(false);
756   }
757 
758   if(m_temporary != obj.m_temporary)
759   {
760     DBUG_PRINT("info",("m_temporary %d != %d",m_temporary,obj.m_temporary));
761     DBUG_RETURN(false);
762   }
763 
764   if(m_row_gci != obj.m_row_gci)
765   {
766     DBUG_PRINT("info",("m_row_gci %d != %d",m_row_gci,obj.m_row_gci));
767     DBUG_RETURN(false);
768   }
769 
770   if(m_row_checksum != obj.m_row_checksum)
771   {
772     DBUG_PRINT("info",("m_row_checksum %d != %d",m_row_checksum,
773                         obj.m_row_checksum));
774     DBUG_RETURN(false);
775   }
776 
777   if(m_kvalue != obj.m_kvalue)
778   {
779     DBUG_PRINT("info",("m_kvalue %d != %d",m_kvalue,obj.m_kvalue));
780     DBUG_RETURN(false);
781   }
782 
783   if(m_minLoadFactor != obj.m_minLoadFactor)
784   {
785     DBUG_PRINT("info",("m_minLoadFactor %d != %d",m_minLoadFactor,
786                         obj.m_minLoadFactor));
787     DBUG_RETURN(false);
788   }
789 
790   if(m_maxLoadFactor != obj.m_maxLoadFactor)
791   {
792     DBUG_PRINT("info",("m_maxLoadFactor %d != %d",m_maxLoadFactor,
793                         obj.m_maxLoadFactor));
794     DBUG_RETURN(false);
795   }
796 
797   if(m_tablespace_id != obj.m_tablespace_id)
798   {
799     DBUG_PRINT("info",("m_tablespace_id %d != %d",m_tablespace_id,
800                         obj.m_tablespace_id));
801     DBUG_RETURN(false);
802   }
803 
804   if(m_tablespace_version != obj.m_tablespace_version)
805   {
806     DBUG_PRINT("info",("m_tablespace_version %d != %d",m_tablespace_version,
807                         obj.m_tablespace_version));
808     DBUG_RETURN(false);
809   }
810 
811   if(m_id != obj.m_id)
812   {
813     DBUG_PRINT("info",("m_id %d != %d",m_id,obj.m_id));
814     DBUG_RETURN(false);
815   }
816 
817   if(m_version != obj.m_version)
818   {
819     DBUG_PRINT("info",("m_version %d != %d",m_version,obj.m_version));
820     DBUG_RETURN(false);
821   }
822 
823   if(m_type != obj.m_type)
824   {
825     DBUG_PRINT("info",("m_type %d != %d",m_type,obj.m_type));
826     DBUG_RETURN(false);
827   }
828 
829   if (m_type == NdbDictionary::Object::UniqueHashIndex ||
830       m_type == NdbDictionary::Object::OrderedIndex)
831   {
832     if(m_primaryTableId != obj.m_primaryTableId)
833     {
834       DBUG_PRINT("info",("m_primaryTableId %d != %d",m_primaryTableId,
835                  obj.m_primaryTableId));
836       DBUG_RETURN(false);
837     }
838     if (m_indexType != obj.m_indexType)
839     {
840       DBUG_PRINT("info",("m_indexType %d != %d",m_indexType,obj.m_indexType));
841       DBUG_RETURN(false);
842     }
843     if(strcmp(m_primaryTable.c_str(), obj.m_primaryTable.c_str()) != 0)
844     {
845       DBUG_PRINT("info",("m_primaryTable %s != %s",
846 			 m_primaryTable.c_str(),obj.m_primaryTable.c_str()));
847       DBUG_RETURN(false);
848     }
849   }
850 
851   if(m_single_user_mode != obj.m_single_user_mode)
852   {
853     DBUG_PRINT("info",("m_single_user_mode %d != %d",
854                        (int32)m_single_user_mode,
855                        (int32)obj.m_single_user_mode));
856     DBUG_RETURN(false);
857   }
858 
859   if (m_extra_row_gci_bits != obj.m_extra_row_gci_bits)
860   {
861     DBUG_PRINT("info",("m_extra_row_gci_bits %d != %d",
862                        (int32)m_extra_row_gci_bits,
863                        (int32)obj.m_extra_row_gci_bits));
864     DBUG_RETURN(false);
865   }
866 
867   if (m_extra_row_author_bits != obj.m_extra_row_author_bits)
868   {
869     DBUG_PRINT("info",("m_extra_row_author_bits %d != %d",
870                        (int32)m_extra_row_author_bits,
871                        (int32)obj.m_extra_row_author_bits));
872     DBUG_RETURN(false);
873   }
874 
875   DBUG_RETURN(true);
876 }
877 
878 int
assign(const NdbTableImpl & org)879 NdbTableImpl::assign(const NdbTableImpl& org)
880 {
881   DBUG_ENTER("NdbTableImpl::assign");
882   DBUG_PRINT("info", ("this: %p  &org: %p", this, &org));
883   m_primaryTableId = org.m_primaryTableId;
884   if (!m_internalName.assign(org.m_internalName) ||
885       updateMysqlName())
886   {
887     DBUG_RETURN(-1);
888   }
889   m_externalName.assign(org.m_externalName);
890   m_frm.assign(org.m_frm.get_data(), org.m_frm.length());
891   m_fd.assign(org.m_fd);
892   m_range.assign(org.m_range);
893 
894   m_fragmentType = org.m_fragmentType;
895   if (m_fragmentType == NdbDictionary::Object::HashMapPartition)
896   {
897     m_hash_map_id = org.m_hash_map_id;
898     m_hash_map_version = org.m_hash_map_version;
899     m_hash_map.assign(org.m_hash_map);
900   }
901   else
902   {
903     m_hash_map_id = RNIL;
904     m_hash_map_version = ~0;
905   }
906   /*
907     m_columnHashMask, m_columnHash, m_hashValueMask, m_hashpointerValue
908     is state calculated by computeAggregates and buildColumnHash
909   */
910   unsigned i;
911   for(i = 0; i < m_columns.size(); i++)
912   {
913     delete m_columns[i];
914   }
915   m_columns.clear();
916   for(i = 0; i < org.m_columns.size(); i++)
917   {
918     NdbColumnImpl * col = new NdbColumnImpl();
919     if (col == NULL)
920     {
921       errno = ENOMEM;
922       DBUG_RETURN(-1);
923     }
924     const NdbColumnImpl * iorg = org.m_columns[i];
925     (* col) = (* iorg);
926     if (m_columns.push_back(col))
927     {
928       delete col;
929       DBUG_RETURN(-1);
930     }
931   }
932 
933   m_fragments = org.m_fragments;
934 
935   m_linear_flag = org.m_linear_flag;
936   m_max_rows = org.m_max_rows;
937   m_default_no_part_flag = org.m_default_no_part_flag;
938   m_logging = org.m_logging;
939   m_temporary = org.m_temporary;
940   m_row_gci = org.m_row_gci;
941   m_row_checksum = org.m_row_checksum;
942   m_force_var_part = org.m_force_var_part;
943   m_has_default_values = org.m_has_default_values;
944   m_kvalue = org.m_kvalue;
945   m_minLoadFactor = org.m_minLoadFactor;
946   m_maxLoadFactor = org.m_maxLoadFactor;
947   m_keyLenInWords = org.m_keyLenInWords;
948   m_fragmentCount = org.m_fragmentCount;
949 
950   m_single_user_mode = org.m_single_user_mode;
951   m_extra_row_gci_bits = org.m_extra_row_gci_bits;
952   m_extra_row_author_bits = org.m_extra_row_author_bits;
953 
954   if (m_index != 0)
955     delete m_index;
956   m_index = org.m_index;
957 
958   m_primaryTable = org.m_primaryTable;
959   m_indexType = org.m_indexType;
960 
961   m_noOfKeys = org.m_noOfKeys;
962   m_noOfDistributionKeys = org.m_noOfDistributionKeys;
963   m_noOfBlobs = org.m_noOfBlobs;
964   m_replicaCount = org.m_replicaCount;
965 
966   m_noOfAutoIncColumns = org.m_noOfAutoIncColumns;
967 
968   m_id = org.m_id;
969   m_version = org.m_version;
970   m_status = org.m_status;
971 
972   m_max_rows = org.m_max_rows;
973   m_min_rows = org.m_min_rows;
974 
975   m_tablespace_name = org.m_tablespace_name;
976   m_tablespace_id= org.m_tablespace_id;
977   m_tablespace_version = org.m_tablespace_version;
978   m_storageType = org.m_storageType;
979 
980   DBUG_RETURN(0);
981 }
982 
setName(const char * name)983 int NdbTableImpl::setName(const char * name)
984 {
985   return !m_externalName.assign(name);
986 }
987 
988 const char *
getName() const989 NdbTableImpl::getName() const
990 {
991   return m_externalName.c_str();
992 }
993 
994 int
getDbName(char buf[],size_t len) const995 NdbTableImpl::getDbName(char buf[], size_t len) const
996 {
997   if (len == 0)
998     return -1;
999 
1000   // db/schema/table
1001   const char *ptr = m_internalName.c_str();
1002 
1003   size_t pos = 0;
1004   while (ptr[pos] && ptr[pos] != table_name_separator)
1005   {
1006     buf[pos] = ptr[pos];
1007     pos++;
1008 
1009     if (pos == len)
1010       return -1;
1011   }
1012   buf[pos] = 0;
1013   return 0;
1014 }
1015 
1016 int
getSchemaName(char buf[],size_t len) const1017 NdbTableImpl::getSchemaName(char buf[], size_t len) const
1018 {
1019   if (len == 0)
1020     return -1;
1021 
1022   // db/schema/table
1023   const char *ptr = m_internalName.c_str();
1024 
1025   // skip over "db"
1026   while (*ptr && *ptr != table_name_separator)
1027     ptr++;
1028 
1029   buf[0] = 0;
1030   if (*ptr == table_name_separator)
1031   {
1032     ptr++;
1033     size_t pos = 0;
1034     while (ptr[pos] && ptr[pos] != table_name_separator)
1035     {
1036       buf[pos] = ptr[pos];
1037       pos++;
1038 
1039       if (pos == len)
1040         return -1;
1041     }
1042     buf[pos] = 0;
1043   }
1044 
1045   return 0;
1046 }
1047 
1048 void
setDbSchema(const char * db,const char * schema)1049 NdbTableImpl::setDbSchema(const char * db, const char * schema)
1050 {
1051   m_internalName.assfmt("%s%c%s%c%s",
1052                         db,
1053                         table_name_separator,
1054                         schema,
1055                         table_name_separator,
1056                         m_externalName.c_str());
1057   updateMysqlName();
1058 }
1059 
1060 void
computeAggregates()1061 NdbTableImpl::computeAggregates()
1062 {
1063   m_noOfKeys = 0;
1064   m_keyLenInWords = 0;
1065   m_noOfDistributionKeys = 0;
1066   m_noOfBlobs = 0;
1067   m_noOfDiskColumns = 0;
1068   Uint32 i, n;
1069   for (i = 0; i < m_columns.size(); i++) {
1070     NdbColumnImpl* col = m_columns[i];
1071     if (col->m_pk) {
1072       m_noOfKeys++;
1073       m_keyLenInWords += (col->m_attrSize * col->m_arraySize + 3) / 4;
1074     }
1075     if (col->m_distributionKey)
1076       m_noOfDistributionKeys++; // XXX check PK
1077 
1078     if (col->getBlobType())
1079       m_noOfBlobs++;
1080 
1081     if (col->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
1082       m_noOfDiskColumns++;
1083 
1084     col->m_keyInfoPos = ~0;
1085 
1086     if (col->m_autoIncrement)
1087       m_noOfAutoIncColumns++;
1088   }
1089   if (m_noOfDistributionKeys == m_noOfKeys) {
1090     // all is none!
1091     m_noOfDistributionKeys = 0;
1092   }
1093 
1094   if (m_noOfDistributionKeys == 0)
1095   {
1096     // none is all!
1097     for (i = 0, n = m_noOfKeys; n != 0; i++) {
1098       NdbColumnImpl* col = m_columns[i];
1099       if (col->m_pk) {
1100         col->m_distributionKey = true;
1101         n--;
1102       }
1103     }
1104   }
1105 
1106   Uint32 keyInfoPos = 0;
1107   for (i = 0, n = m_noOfKeys; n != 0; i++) {
1108     NdbColumnImpl* col = m_columns[i];
1109     if (col->m_pk) {
1110       col->m_keyInfoPos = keyInfoPos++;
1111       n--;
1112     }
1113   }
1114 }
1115 
1116 // TODO add error checks
1117 // TODO use these internally at create and retrieve
1118 int
aggregate(NdbError & error)1119 NdbTableImpl::aggregate(NdbError& error)
1120 {
1121   computeAggregates();
1122   return 0;
1123 }
1124 int
validate(NdbError & error)1125 NdbTableImpl::validate(NdbError& error)
1126 {
1127   if (aggregate(error) == -1)
1128     return -1;
1129   return 0;
1130 }
1131 
1132 void
setFragmentCount(Uint32 count)1133 NdbTableImpl::setFragmentCount(Uint32 count)
1134 {
1135   m_fragmentCount= count;
1136 }
1137 
getFragmentCount() const1138 Uint32 NdbTableImpl::getFragmentCount() const
1139 {
1140   return m_fragmentCount;
1141 }
1142 
setFrm(const void * data,Uint32 len)1143 int NdbTableImpl::setFrm(const void* data, Uint32 len)
1144 {
1145   return m_frm.assign(data, len);
1146 }
1147 
1148 const void *
getFrmData() const1149 NdbTableImpl::getFrmData() const
1150 {
1151   return m_frm.get_data();
1152 }
1153 
1154 Uint32
getFrmLength() const1155 NdbTableImpl::getFrmLength() const
1156 {
1157   return m_frm.length();
1158 }
1159 
1160 int
setFragmentData(const Uint32 * data,Uint32 cnt)1161 NdbTableImpl::setFragmentData(const Uint32* data, Uint32 cnt)
1162 {
1163   return m_fd.assign(data, cnt);
1164 }
1165 
1166 const Uint32 *
getFragmentData() const1167 NdbTableImpl::getFragmentData() const
1168 {
1169   return m_fd.getBase();
1170 }
1171 
1172 Uint32
getFragmentDataLen() const1173 NdbTableImpl::getFragmentDataLen() const
1174 {
1175   return m_fd.size();
1176 }
1177 
1178 int
setRangeListData(const Int32 * data,Uint32 len)1179 NdbTableImpl::setRangeListData(const Int32* data, Uint32 len)
1180 {
1181   return m_range.assign(data, len);
1182 }
1183 
1184 const Int32 *
getRangeListData() const1185 NdbTableImpl::getRangeListData() const
1186 {
1187   return m_range.getBase();
1188 }
1189 
1190 Uint32
getRangeListDataLen() const1191 NdbTableImpl::getRangeListDataLen() const
1192 {
1193   return m_range.size();
1194 }
1195 
1196 Uint32
getFragmentNodes(Uint32 fragmentId,Uint32 * nodeIdArrayPtr,Uint32 arraySize) const1197 NdbTableImpl::getFragmentNodes(Uint32 fragmentId,
1198                                Uint32* nodeIdArrayPtr,
1199                                Uint32 arraySize) const
1200 {
1201   const Uint16 *shortNodeIds;
1202   Uint32 nodeCount = get_nodes(fragmentId, &shortNodeIds);
1203 
1204   for(Uint32 i = 0;
1205       ((i < nodeCount) &&
1206        (i < arraySize));
1207       i++)
1208     nodeIdArrayPtr[i] = (Uint32) shortNodeIds[i];
1209 
1210   return nodeCount;
1211 }
1212 
1213 int
updateMysqlName()1214 NdbTableImpl::updateMysqlName()
1215 {
1216   Vector<BaseString> v;
1217   if (m_internalName.split(v,"/") == 3)
1218   {
1219     return !m_mysqlName.assfmt("%s/%s",v[0].c_str(),v[2].c_str());
1220   }
1221   return !m_mysqlName.assign("");
1222 }
1223 
1224 int
buildColumnHash()1225 NdbTableImpl::buildColumnHash(){
1226   const Uint32 size = m_columns.size();
1227   int i;
1228   for(i = 31; i >= 0; i--){
1229     if(((1 << i) & size) != 0){
1230       m_columnHashMask = (1 << (i + 1)) - 1;
1231       break;
1232     }
1233   }
1234 
1235   Vector<Uint32> hashValues;
1236   Vector<Vector<Uint32> > chains;
1237   if (chains.fill(size, hashValues))
1238   {
1239     return -1;
1240   }
1241   for(i = 0; i< (int) size; i++){
1242     Uint32 hv = Hash(m_columns[i]->getName()) & 0xFFFE;
1243     Uint32 bucket = hv & m_columnHashMask;
1244     bucket = (bucket < size ? bucket : bucket - size);
1245     assert(bucket < size);
1246     if (hashValues.push_back(hv) ||
1247         chains[bucket].push_back(i))
1248     {
1249       return -1;
1250     }
1251   }
1252 
1253   m_columnHash.clear();
1254   Uint32 tmp = 1;
1255   if (m_columnHash.fill((unsigned)size-1, tmp))   // Default no chaining
1256   {
1257     return -1;
1258   }
1259 
1260   Uint32 pos = 0; // In overflow vector
1261   for(i = 0; i< (int) size; i++){
1262     Uint32 sz = chains[i].size();
1263     if(sz == 1){
1264       Uint32 col = chains[i][0];
1265       Uint32 hv = hashValues[col];
1266       Uint32 bucket = hv & m_columnHashMask;
1267       bucket = (bucket < size ? bucket : bucket - size);
1268       m_columnHash[bucket] = (col << 16) | hv | 1;
1269     } else if(sz > 1){
1270       Uint32 col = chains[i][0];
1271       Uint32 hv = hashValues[col];
1272       Uint32 bucket = hv & m_columnHashMask;
1273       bucket = (bucket < size ? bucket : bucket - size);
1274       m_columnHash[bucket] = (sz << 16) | (((size - bucket) + pos) << 1);
1275       for(unsigned j = 0; j<sz; j++, pos++){
1276 	Uint32 col = chains[i][j];
1277 	Uint32 hv = hashValues[col];
1278 	if (m_columnHash.push_back((col << 16) | hv))
1279         {
1280           return -1;
1281         }
1282       }
1283     }
1284   }
1285 
1286   if (m_columnHash.push_back(0)) // Overflow when looping in end of array
1287   {
1288     return -1;
1289   }
1290 
1291 #if 0
1292   for(size_t i = 0; i<m_columnHash.size(); i++){
1293     Uint32 tmp = m_columnHash[i];
1294     int col = -1;
1295     if(i < size && (tmp & 1) == 1){
1296       col = (tmp >> 16);
1297     } else if(i >= size){
1298       col = (tmp >> 16);
1299     }
1300     ndbout_c("m_columnHash[%d] %s = %x",
1301 	     i, col > 0 ? m_columns[col]->getName() : "" , m_columnHash[i]);
1302   }
1303 #endif
1304   return 0;
1305 }
1306 
1307 Uint32
get_nodes(Uint32 fragmentId,const Uint16 ** nodes) const1308 NdbTableImpl::get_nodes(Uint32 fragmentId, const Uint16 ** nodes) const
1309 {
1310   Uint32 pos = fragmentId * m_replicaCount;
1311   if (pos + m_replicaCount <= m_fragments.size())
1312   {
1313     *nodes = m_fragments.getBase()+pos;
1314     return m_replicaCount;
1315   }
1316   return 0;
1317 }
1318 
1319 int
checkColumns(const Uint32 * map,Uint32 len) const1320 NdbDictionary::Table::checkColumns(const Uint32* map, Uint32 len) const
1321 {
1322   int ret = 0;
1323   Uint32 colCnt = m_impl.m_columns.size();
1324   if (map == 0)
1325   {
1326     ret |= 1;
1327     ret |= (m_impl.m_noOfDiskColumns) ? 2 : 0;
1328     ret |= (colCnt > m_impl.m_noOfDiskColumns) ? 4 : 0;
1329     return ret;
1330   }
1331 
1332   NdbColumnImpl** cols = m_impl.m_columns.getBase();
1333   const char * ptr = reinterpret_cast<const char*>(map);
1334   const char * end = ptr + len;
1335   Uint32 no = 0;
1336   while (ptr < end)
1337   {
1338     Uint32 val = (Uint32)* ptr;
1339     Uint32 idx = 1;
1340     for (Uint32 i = 0; i<8; i++)
1341     {
1342       if (val & idx)
1343       {
1344 	if (cols[no]->getPrimaryKey())
1345 	  ret |= 1;
1346 	else
1347 	{
1348 	  if (cols[no]->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
1349 	    ret |= 2;
1350 	  else
1351 	    ret |= 4;
1352 	}
1353       }
1354       no ++;
1355       idx *= 2;
1356       if (no == colCnt)
1357 	return ret;
1358     }
1359 
1360     ptr++;
1361   }
1362   return ret;
1363 }
1364 
1365 
1366 
1367 /**
1368  * NdbIndexImpl
1369  */
1370 
NdbIndexImpl()1371 NdbIndexImpl::NdbIndexImpl() :
1372   NdbDictionary::Index(* this),
1373   NdbDictObjectImpl(NdbDictionary::Object::OrderedIndex), m_facade(this)
1374 {
1375   init();
1376 }
1377 
NdbIndexImpl(NdbDictionary::Index & f)1378 NdbIndexImpl::NdbIndexImpl(NdbDictionary::Index & f) :
1379   NdbDictionary::Index(* this),
1380   NdbDictObjectImpl(NdbDictionary::Object::OrderedIndex), m_facade(&f)
1381 {
1382   init();
1383 }
1384 
init()1385 void NdbIndexImpl::init()
1386 {
1387   m_id= RNIL;
1388   m_type= NdbDictionary::Object::TypeUndefined;
1389   m_logging= true;
1390   m_temporary= false;
1391   m_table= NULL;
1392 }
1393 
~NdbIndexImpl()1394 NdbIndexImpl::~NdbIndexImpl(){
1395   for (unsigned i = 0; i < m_columns.size(); i++)
1396     delete m_columns[i];
1397 }
1398 
setName(const char * name)1399 int NdbIndexImpl::setName(const char * name)
1400 {
1401   return !m_externalName.assign(name);
1402 }
1403 
1404 const char *
getName() const1405 NdbIndexImpl::getName() const
1406 {
1407   return m_externalName.c_str();
1408 }
1409 
1410 int
setTable(const char * table)1411 NdbIndexImpl::setTable(const char * table)
1412 {
1413   return !m_tableName.assign(table);
1414 }
1415 
1416 const char *
getTable() const1417 NdbIndexImpl::getTable() const
1418 {
1419   return m_tableName.c_str();
1420 }
1421 
1422 const NdbTableImpl *
getIndexTable() const1423 NdbIndexImpl::getIndexTable() const
1424 {
1425   return m_table;
1426 }
1427 
1428 /**
1429  * NdbOptimizeTableHandleImpl
1430  */
1431 
NdbOptimizeTableHandleImpl(NdbDictionary::OptimizeTableHandle & f)1432 NdbOptimizeTableHandleImpl::NdbOptimizeTableHandleImpl(NdbDictionary::OptimizeTableHandle &f)
1433   : NdbDictionary::OptimizeTableHandle(* this),
1434     m_state(NdbOptimizeTableHandleImpl::CREATED),
1435     m_ndb(NULL), m_table(NULL),
1436     m_table_queue(NULL), m_table_queue_first(NULL), m_table_queue_end(NULL),
1437     m_trans(NULL), m_scan_op(NULL),
1438     m_facade(this)
1439 {
1440 }
1441 
~NdbOptimizeTableHandleImpl()1442 NdbOptimizeTableHandleImpl::~NdbOptimizeTableHandleImpl()
1443 {
1444   DBUG_ENTER("NdbOptimizeTableHandleImpl::~NdbOptimizeTableHandleImpl");
1445   close();
1446   DBUG_VOID_RETURN;
1447 }
1448 
start()1449 int NdbOptimizeTableHandleImpl::start()
1450 {
1451   int noRetries = 100;
1452   DBUG_ENTER("NdbOptimizeTableImpl::start");
1453 
1454   if (m_table_queue)
1455   {
1456     const NdbTableImpl * table = m_table_queue->table;
1457 
1458     /*
1459      * Start/Restart transaction
1460      */
1461     while (noRetries-- > 0)
1462     {
1463       if (m_trans && (m_trans->restart() != 0))
1464       {
1465         m_ndb->closeTransaction(m_trans);
1466         m_trans = NULL;
1467       }
1468       else
1469         m_trans = m_ndb->startTransaction();
1470       if (!m_trans)
1471       {
1472         if (noRetries == 0)
1473           goto do_error;
1474         continue;
1475       }
1476 
1477       /*
1478        * Get first scan operation
1479        */
1480       if ((m_scan_op = m_trans->getNdbScanOperation(table->m_facade))
1481           == NULL)
1482       {
1483         m_ndb->getNdbError(m_trans->getNdbError().code);
1484         goto do_error;
1485       }
1486 
1487       /**
1488        * Define a result set for the scan.
1489        */
1490       if (m_scan_op->readTuples(NdbOperation::LM_Exclusive)) {
1491         m_ndb->getNdbError(m_trans->getNdbError().code);
1492         goto do_error;
1493       }
1494 
1495       /**
1496        * Start scan    (NoCommit since we are only reading at this stage);
1497        */
1498       if (m_trans->execute(NdbTransaction::NoCommit) != 0) {
1499         if (m_trans->getNdbError().status == NdbError::TemporaryError)
1500           continue;  /* goto next_retry */
1501         m_ndb->getNdbError(m_trans->getNdbError().code);
1502         goto do_error;
1503       }
1504       break;
1505     } // while (noRetries-- > 0)
1506     m_state = NdbOptimizeTableHandleImpl::INITIALIZED;
1507   } // if (m_table_queue)
1508   else
1509     m_state = NdbOptimizeTableHandleImpl::FINISHED;
1510 
1511   DBUG_RETURN(0);
1512 do_error:
1513   DBUG_PRINT("info", ("NdbOptimizeTableImpl::start aborted"));
1514   m_state = NdbOptimizeTableHandleImpl::ABORTED;
1515   DBUG_RETURN(-1);
1516 }
1517 
init(Ndb * ndb,const NdbTableImpl & table)1518 int NdbOptimizeTableHandleImpl::init(Ndb* ndb, const NdbTableImpl &table)
1519 {
1520   DBUG_ENTER("NdbOptimizeTableHandleImpl::init");
1521   NdbDictionary::Dictionary* dict = ndb->getDictionary();
1522   Uint32 sz = table.m_columns.size();
1523   bool found_varpart = false;
1524   int blob_num = table.m_noOfBlobs;
1525 
1526   m_ndb = ndb;
1527   m_table = &table;
1528 
1529   /**
1530    * search whether there are var size columns in the table,
1531    * in first step, we only optimize var part, then if the
1532    * table has no var size columns, we do not do optimizing
1533    */
1534   for (Uint32 i = 0; i < sz; i++) {
1535     const NdbColumnImpl *col = m_table->m_columns[i];
1536     if (col != 0 && col->m_storageType == NDB_STORAGETYPE_MEMORY &&
1537         (col->m_dynamic || col->m_arrayType != NDB_ARRAYTYPE_FIXED)) {
1538       found_varpart= true;
1539       break;
1540     }
1541   }
1542   if (!found_varpart)
1543   {
1544     m_state = NdbOptimizeTableHandleImpl::FINISHED;
1545     DBUG_RETURN(0);
1546   }
1547 
1548   /*
1549    * Add main table to the table queue
1550    * to optimize
1551    */
1552   m_table_queue_end = new fifo_element_st(m_table, m_table_queue_end);
1553   m_table_queue = m_table_queue_first = m_table_queue_end;
1554   /*
1555    * Add any BLOB tables the table queue
1556    * to optimize.
1557    */
1558   for (int i = m_table->m_columns.size(); i > 0 && blob_num > 0;) {
1559     i--;
1560     NdbColumnImpl & c = *m_table->m_columns[i];
1561     if (! c.getBlobType() || c.getPartSize() == 0)
1562       continue;
1563 
1564     blob_num--;
1565     const NdbTableImpl * blob_table =
1566       (const NdbTableImpl *)dict->getBlobTable(m_table, c.m_attrId);
1567     if (blob_table)
1568     {
1569       m_table_queue_end = new fifo_element_st(blob_table, m_table_queue_end);
1570     }
1571   }
1572   /*
1573    * Initialize transaction
1574    */
1575   DBUG_RETURN(start());
1576 }
1577 
next()1578 int NdbOptimizeTableHandleImpl::next()
1579 {
1580   int noRetries = 100;
1581   int done, check;
1582   DBUG_ENTER("NdbOptimizeTableHandleImpl::next");
1583 
1584   if (m_state == NdbOptimizeTableHandleImpl::FINISHED)
1585     DBUG_RETURN(0);
1586   else if (m_state != NdbOptimizeTableHandleImpl::INITIALIZED)
1587     DBUG_RETURN(-1);
1588 
1589   while (noRetries-- > 0)
1590   {
1591     if ((done = check = m_scan_op->nextResult(true)) == 0)
1592     {
1593       do
1594       {
1595         /**
1596          * Get update operation
1597          */
1598         NdbOperation * myUpdateOp = m_scan_op->updateCurrentTuple();
1599         if (myUpdateOp == 0)
1600         {
1601           m_ndb->getNdbError(m_trans->getNdbError().code);
1602           goto do_error;
1603         }
1604         /**
1605          * optimize a tuple through doing the update
1606          * first step, move varpart
1607          */
1608         Uint32 options = 0 | AttributeHeader::OPTIMIZE_MOVE_VARPART;
1609         myUpdateOp->setOptimize(options);
1610         /**
1611          * nextResult(false) means that the records
1612          * cached in the NDBAPI are modified before
1613          * fetching more rows from NDB.
1614          */
1615       } while ((check = m_scan_op->nextResult(false)) == 0);
1616     }
1617 
1618     /**
1619      * Commit when all cached tuple have been updated
1620      */
1621     if (check != -1)
1622       check = m_trans->execute(NdbTransaction::Commit);
1623 
1624     if (done == 1)
1625     {
1626       DBUG_PRINT("info", ("Done with table %s",
1627                           m_table_queue->table->getName()));
1628       /*
1629        * We are done with optimizing current table
1630        * move to next
1631        */
1632       fifo_element_st *current = m_table_queue;
1633       m_table_queue = current->next;
1634       /*
1635        * Start scan of next table
1636        */
1637       if (start() != 0) {
1638         m_ndb->getNdbError(m_trans->getNdbError().code);
1639         goto do_error;
1640       }
1641       DBUG_RETURN(1);
1642     }
1643     if (check == -1)
1644     {
1645       if (m_trans->getNdbError().status == NdbError::TemporaryError)
1646       {
1647         /*
1648          * If we encountered temporary error, retry
1649          */
1650         m_ndb->closeTransaction(m_trans);
1651         m_trans = NULL;
1652         if (start() != 0) {
1653           m_ndb->getNdbError(m_trans->getNdbError().code);
1654           goto do_error;
1655         }
1656         continue; //retry
1657       }
1658       m_ndb->getNdbError(m_trans->getNdbError().code);
1659       goto do_error;
1660     }
1661     if (m_trans->restart() != 0)
1662     {
1663       DBUG_PRINT("info", ("Failed to restart transaction"));
1664       m_ndb->closeTransaction(m_trans);
1665       m_trans = NULL;
1666       if (start() != 0) {
1667         m_ndb->getNdbError(m_trans->getNdbError().code);
1668         goto do_error;
1669       }
1670     }
1671 
1672     DBUG_RETURN(1);
1673   }
1674 do_error:
1675   DBUG_PRINT("info", ("NdbOptimizeTableHandleImpl::next aborted"));
1676   m_state = NdbOptimizeTableHandleImpl::ABORTED;
1677   DBUG_RETURN(-1);
1678 }
1679 
close()1680 int NdbOptimizeTableHandleImpl::close()
1681 {
1682   DBUG_ENTER("NdbOptimizeTableHandleImpl::close");
1683   /*
1684    * Drop queued tables
1685    */
1686   while(m_table_queue_first != NULL)
1687   {
1688     fifo_element_st *next = m_table_queue_first->next;
1689     delete m_table_queue_first;
1690     m_table_queue_first = next;
1691   }
1692   m_table_queue = m_table_queue_first = m_table_queue_end = NULL;
1693   if (m_trans)
1694   {
1695     m_ndb->closeTransaction(m_trans);
1696     m_trans = NULL;
1697   }
1698   m_state = NdbOptimizeTableHandleImpl::CLOSED;
1699   DBUG_RETURN(0);
1700 }
1701 
1702 /**
1703  * NdbOptimizeIndexHandleImpl
1704  */
1705 
NdbOptimizeIndexHandleImpl(NdbDictionary::OptimizeIndexHandle & f)1706 NdbOptimizeIndexHandleImpl::NdbOptimizeIndexHandleImpl(NdbDictionary::OptimizeIndexHandle &f)
1707   : NdbDictionary::OptimizeIndexHandle(* this),
1708     m_state(NdbOptimizeIndexHandleImpl::CREATED),
1709     m_ndb(NULL), m_index(NULL),
1710     m_facade(this)
1711 {
1712   DBUG_ENTER("NdbOptimizeIndexHandleImpl::NdbOptimizeIndexHandleImpl");
1713   DBUG_VOID_RETURN;
1714 }
1715 
~NdbOptimizeIndexHandleImpl()1716 NdbOptimizeIndexHandleImpl::~NdbOptimizeIndexHandleImpl()
1717 {
1718   DBUG_ENTER("NdbOptimizeIndexHandleImpl::~NdbOptimizeIndexHandleImpl");
1719   DBUG_VOID_RETURN;
1720 }
1721 
init(Ndb * ndb,const NdbIndexImpl & index)1722 int NdbOptimizeIndexHandleImpl::init(Ndb *ndb, const NdbIndexImpl &index)
1723 {
1724   DBUG_ENTER("NdbOptimizeIndexHandleImpl::init");
1725   m_index = &index;
1726   m_state = NdbOptimizeIndexHandleImpl::INITIALIZED;
1727   /**
1728    * NOTE: we only optimize unique index
1729    */
1730   if (m_index->m_facade->getType() != NdbDictionary::Index::UniqueHashIndex)
1731     DBUG_RETURN(0);
1732   DBUG_RETURN(m_optimize_table_handle.m_impl.init(ndb, *index.getIndexTable()));
1733 }
1734 
next()1735 int NdbOptimizeIndexHandleImpl::next()
1736 {
1737   DBUG_ENTER("NdbOptimizeIndexHandleImpl::next");
1738   if (m_state != NdbOptimizeIndexHandleImpl::INITIALIZED)
1739     DBUG_RETURN(0);
1740   if (m_index->m_facade->getType() != NdbDictionary::Index::UniqueHashIndex)
1741     DBUG_RETURN(0);
1742   DBUG_RETURN(m_optimize_table_handle.m_impl.next());
1743 }
1744 
close()1745 int NdbOptimizeIndexHandleImpl::close()
1746 {
1747   DBUG_ENTER("NdbOptimizeIndexHandleImpl::close");
1748   m_state = NdbOptimizeIndexHandleImpl::CLOSED;
1749   if (m_index &&
1750       m_index->m_facade->getType() == NdbDictionary::Index::UniqueHashIndex)
1751     DBUG_RETURN(m_optimize_table_handle.m_impl.close());
1752 
1753   DBUG_RETURN(0);
1754 }
1755 
1756 /**
1757  * NdbEventImpl
1758  */
1759 
NdbEventImpl()1760 NdbEventImpl::NdbEventImpl() :
1761   NdbDictionary::Event(* this),
1762   NdbDictObjectImpl(NdbDictionary::Object::TypeUndefined), m_facade(this)
1763 {
1764   DBUG_ENTER("NdbEventImpl::NdbEventImpl");
1765   DBUG_PRINT("info", ("this: %p", this));
1766   init();
1767   DBUG_VOID_RETURN;
1768 }
1769 
NdbEventImpl(NdbDictionary::Event & f)1770 NdbEventImpl::NdbEventImpl(NdbDictionary::Event & f) :
1771   NdbDictionary::Event(* this),
1772   NdbDictObjectImpl(NdbDictionary::Object::TypeUndefined), m_facade(&f)
1773 {
1774   DBUG_ENTER("NdbEventImpl::NdbEventImpl");
1775   DBUG_PRINT("info", ("this: %p", this));
1776   init();
1777   DBUG_VOID_RETURN;
1778 }
1779 
init()1780 void NdbEventImpl::init()
1781 {
1782   m_eventId= RNIL;
1783   m_eventKey= RNIL;
1784   mi_type= 0;
1785   m_dur= NdbDictionary::Event::ED_UNDEFINED;
1786   m_mergeEvents = false;
1787   m_tableImpl= NULL;
1788   m_rep= NdbDictionary::Event::ER_UPDATED;
1789 }
1790 
~NdbEventImpl()1791 NdbEventImpl::~NdbEventImpl()
1792 {
1793   DBUG_ENTER("NdbEventImpl::~NdbEventImpl");
1794   DBUG_PRINT("info", ("this: %p", this));
1795   for (unsigned i = 0; i < m_columns.size(); i++)
1796     delete  m_columns[i];
1797   if (m_tableImpl)
1798     delete m_tableImpl;
1799   DBUG_VOID_RETURN;
1800 }
1801 
setName(const char * name)1802 int NdbEventImpl::setName(const char * name)
1803 {
1804   return !m_name.assign(name);
1805 }
1806 
getName() const1807 const char *NdbEventImpl::getName() const
1808 {
1809   return m_name.c_str();
1810 }
1811 
1812 int
setTable(const NdbDictionary::Table & table)1813 NdbEventImpl::setTable(const NdbDictionary::Table& table)
1814 {
1815   setTable(&NdbTableImpl::getImpl(table));
1816   return !m_tableName.assign(m_tableImpl->getName());
1817 }
1818 
1819 int
setTable(const NdbDictionary::Table * table)1820 NdbEventImpl::setTable(const NdbDictionary::Table *table)
1821 {
1822   DBUG_ENTER("NdbEventImpl::setTable(const NdbDictionary::Table *table)");
1823   if (table == 0)
1824   {
1825     DBUG_PRINT("info", ("NdbEventImpl::setTable() this: %p invalid table ptr %p", this, table));
1826     DBUG_RETURN(-1);
1827   }
1828   setTable(&NdbTableImpl::getImpl(*table));
1829   DBUG_RETURN(!m_tableName.assign(m_tableImpl->getName()));
1830 }
1831 
1832 void
setTable(NdbTableImpl * tableImpl)1833 NdbEventImpl::setTable(NdbTableImpl *tableImpl)
1834 {
1835   DBUG_ENTER("NdbEventImpl::setTable");
1836   DBUG_PRINT("info", ("this: %p  tableImpl: %p", this, tableImpl));
1837 
1838   if (!m_tableImpl)
1839     m_tableImpl = new NdbTableImpl();
1840   // Copy table, since event might be accessed from different threads
1841   m_tableImpl->assign(*tableImpl);
1842   DBUG_VOID_RETURN;
1843 }
1844 
1845 const NdbDictionary::Table *
getTable() const1846 NdbEventImpl::getTable() const
1847 {
1848   if (m_tableImpl)
1849     return m_tableImpl->m_facade;
1850   else
1851     return NULL;
1852 }
1853 
1854 int
setTable(const char * table)1855 NdbEventImpl::setTable(const char * table)
1856 {
1857   return !m_tableName.assign(table);
1858 }
1859 
1860 const char *
getTableName() const1861 NdbEventImpl::getTableName() const
1862 {
1863   return m_tableName.c_str();
1864 }
1865 
1866 void
addTableEvent(const NdbDictionary::Event::TableEvent t=NdbDictionary::Event::TE_ALL)1867 NdbEventImpl::addTableEvent(const NdbDictionary::Event::TableEvent t =  NdbDictionary::Event::TE_ALL)
1868 {
1869   mi_type |= (unsigned)t;
1870 }
1871 
1872 bool
getTableEvent(const NdbDictionary::Event::TableEvent t) const1873 NdbEventImpl::getTableEvent(const NdbDictionary::Event::TableEvent t) const
1874 {
1875   return (mi_type & (unsigned)t) == (unsigned)t;
1876 }
1877 
1878 void
setDurability(NdbDictionary::Event::EventDurability d)1879 NdbEventImpl::setDurability(NdbDictionary::Event::EventDurability d)
1880 {
1881   m_dur = d;
1882 }
1883 
1884 NdbDictionary::Event::EventDurability
getDurability() const1885 NdbEventImpl::getDurability() const
1886 {
1887   return m_dur;
1888 }
1889 
1890 void
setReport(NdbDictionary::Event::EventReport r)1891 NdbEventImpl::setReport(NdbDictionary::Event::EventReport r)
1892 {
1893   m_rep = r;
1894 }
1895 
1896 NdbDictionary::Event::EventReport
getReport() const1897 NdbEventImpl::getReport() const
1898 {
1899   return m_rep;
1900 }
1901 
getNoOfEventColumns() const1902 int NdbEventImpl::getNoOfEventColumns() const
1903 {
1904   return m_attrIds.size() + m_columns.size();
1905 }
1906 
1907 const NdbDictionary::Column *
getEventColumn(unsigned no) const1908 NdbEventImpl::getEventColumn(unsigned no) const
1909 {
1910   if (m_columns.size())
1911   {
1912     if (no < m_columns.size())
1913     {
1914       return m_columns[no];
1915     }
1916   }
1917   else if (m_attrIds.size())
1918   {
1919     if (no < m_attrIds.size())
1920     {
1921       NdbTableImpl* tab= m_tableImpl;
1922       if (tab == 0)
1923         return 0;
1924       return tab->getColumn(m_attrIds[no]);
1925     }
1926   }
1927   return 0;
1928 }
1929 
1930 /**
1931  * NdbDictionaryImpl
1932  */
1933 
1934 /* Initialise static */
1935 const Uint32
1936 NdbDictionaryImpl::m_emptyMask[MAXNROFATTRIBUTESINWORDS]= {0,0,0,0};
1937 
NdbDictionaryImpl(Ndb & ndb)1938 NdbDictionaryImpl::NdbDictionaryImpl(Ndb &ndb)
1939   : NdbDictionary::Dictionary(* this),
1940     m_facade(this),
1941     m_receiver(m_tx, m_error, m_warn),
1942     m_ndb(ndb)
1943 {
1944   m_globalHash = 0;
1945   m_local_table_data_size= 0;
1946 #ifdef VM_TRACE
1947   STATIC_ASSERT(
1948     (int)WarnUndobufferRoundUp == (int)CreateFilegroupConf::WarnUndobufferRoundUp &&
1949     (int)WarnUndofileRoundDown == (int)CreateFileConf::WarnUndofileRoundDown &&
1950     (int)WarnExtentRoundUp == (int)CreateFilegroupConf::WarnExtentRoundUp &&
1951     (int)WarnDatafileRoundDown == (int)CreateFileConf::WarnDatafileRoundDown &&
1952     (int)WarnDatafileRoundUp == (int)CreateFileConf::WarnDatafileRoundUp
1953   );
1954 #endif
1955 }
1956 
NdbDictionaryImpl(Ndb & ndb,NdbDictionary::Dictionary & f)1957 NdbDictionaryImpl::NdbDictionaryImpl(Ndb &ndb,
1958 				     NdbDictionary::Dictionary & f)
1959   : NdbDictionary::Dictionary(* this),
1960     m_facade(&f),
1961     m_receiver(m_tx, m_error, m_warn),
1962     m_ndb(ndb)
1963 {
1964   m_globalHash = 0;
1965   m_local_table_data_size= 0;
1966 }
1967 
~NdbDictionaryImpl()1968 NdbDictionaryImpl::~NdbDictionaryImpl()
1969 {
1970   /* Release local table references back to the global cache */
1971   NdbElement_t<Ndb_local_table_info> * curr = m_localHash.m_tableHash.getNext(0);
1972   if(m_globalHash){
1973     while(curr != 0){
1974       m_globalHash->lock();
1975       m_globalHash->release(curr->theData->m_table_impl);
1976       Ndb_local_table_info::destroy(curr->theData);
1977       m_globalHash->unlock();
1978 
1979       curr = m_localHash.m_tableHash.getNext(curr);
1980     }
1981   } else {
1982     assert(curr == 0);
1983   }
1984 }
1985 
1986 NdbTableImpl *
fetchGlobalTableImplRef(const GlobalCacheInitObject & obj)1987 NdbDictionaryImpl::fetchGlobalTableImplRef(const GlobalCacheInitObject &obj)
1988 {
1989   DBUG_ENTER("fetchGlobalTableImplRef");
1990   NdbTableImpl *impl;
1991   int error= 0;
1992 
1993   m_globalHash->lock();
1994   impl = m_globalHash->get(obj.m_name.c_str(), &error);
1995   m_globalHash->unlock();
1996 
1997   if (impl == 0){
1998     if (error == 0)
1999       impl = m_receiver.getTable(obj.m_name,
2000                                  m_ndb.usingFullyQualifiedNames());
2001     else
2002       m_error.code = 4000;
2003     if (impl != 0 && (obj.init(this, *impl)))
2004     {
2005       delete impl;
2006       impl = 0;
2007     }
2008     m_globalHash->lock();
2009     m_globalHash->put(obj.m_name.c_str(), impl);
2010     m_globalHash->unlock();
2011   }
2012 
2013   DBUG_RETURN(impl);
2014 }
2015 
2016 void
putTable(NdbTableImpl * impl)2017 NdbDictionaryImpl::putTable(NdbTableImpl *impl)
2018 {
2019   NdbTableImpl *old;
2020 
2021   int ret = getBlobTables(*impl);
2022   int error = 0;
2023   (void)ret;
2024   assert(ret == 0);
2025 
2026   m_globalHash->lock();
2027   if ((old= m_globalHash->get(impl->m_internalName.c_str(), &error)))
2028   {
2029     m_globalHash->alter_table_rep(old->m_internalName.c_str(),
2030                                   impl->m_id,
2031                                   impl->m_version,
2032                                   FALSE);
2033   }
2034   m_globalHash->put(impl->m_internalName.c_str(), impl);
2035   m_globalHash->unlock();
2036   Ndb_local_table_info *info=
2037     Ndb_local_table_info::create(impl, m_local_table_data_size);
2038 
2039   m_localHash.put(impl->m_internalName.c_str(), info);
2040 }
2041 
2042 int
getBlobTables(NdbTableImpl & t)2043 NdbDictionaryImpl::getBlobTables(NdbTableImpl &t)
2044 {
2045   unsigned n= t.m_noOfBlobs;
2046   DBUG_ENTER("NdbDictionaryImpl::getBlobTables");
2047   // optimized for blob column being the last one
2048   // and not looking for more than one if not neccessary
2049   for (unsigned i = t.m_columns.size(); i > 0 && n > 0;) {
2050     i--;
2051     NdbColumnImpl & c = *t.m_columns[i];
2052     if (! c.getBlobType() || c.getPartSize() == 0)
2053       continue;
2054     n--;
2055     // retrieve blob table def from DICT - by-pass cache
2056     char btname[NdbBlobImpl::BlobTableNameSize];
2057     NdbBlob::getBlobTableName(btname, &t, &c);
2058     BaseString btname_internal = m_ndb.internalize_table_name(btname);
2059     NdbTableImpl* bt =
2060       m_receiver.getTable(btname_internal, m_ndb.usingFullyQualifiedNames());
2061     if (bt == NULL)
2062     {
2063       if (ignore_broken_blob_tables())
2064       {
2065         DBUG_PRINT("info", ("Blob table %s not found, continuing", btname));
2066         continue;
2067       }
2068       DBUG_RETURN(-1);
2069     }
2070 
2071     // TODO check primary id/version when returned by DICT
2072 
2073     // the blob column owns the blob table
2074     assert(c.m_blobTable == NULL);
2075     c.m_blobTable = bt;
2076 
2077     // change storage type to that of PART column
2078     const char* colName = c.m_blobVersion == 1 ? "DATA" : "NDB$DATA";
2079     const NdbColumnImpl* bc = bt->getColumn(colName);
2080     assert(bc != 0);
2081     assert(c.m_storageType == NDB_STORAGETYPE_MEMORY);
2082     c.m_storageType = bc->m_storageType;
2083   }
2084   DBUG_RETURN(0);
2085 }
2086 
2087 NdbTableImpl*
getBlobTable(const NdbTableImpl & tab,uint col_no)2088 NdbDictionaryImpl::getBlobTable(const NdbTableImpl& tab, uint col_no)
2089 {
2090   if (col_no < tab.m_columns.size()) {
2091     NdbColumnImpl* col = tab.m_columns[col_no];
2092     if (col != NULL) {
2093       NdbTableImpl* bt = col->m_blobTable;
2094       if (bt != NULL)
2095         return bt;
2096       else
2097         m_error.code = 4273; // No blob table..
2098     } else
2099       m_error.code = 4249; // Invalid table..
2100   } else
2101     m_error.code = 4318; // Invalid attribute..
2102   return NULL;
2103 }
2104 
2105 NdbTableImpl*
getBlobTable(uint tab_id,uint col_no)2106 NdbDictionaryImpl::getBlobTable(uint tab_id, uint col_no)
2107 {
2108   DBUG_ENTER("NdbDictionaryImpl::getBlobTable");
2109   DBUG_PRINT("enter", ("tab_id: %u col_no %u", tab_id, col_no));
2110 
2111   NdbTableImpl* tab = m_receiver.getTable(tab_id,
2112                                           m_ndb.usingFullyQualifiedNames());
2113   if (tab == NULL)
2114     DBUG_RETURN(NULL);
2115   Ndb_local_table_info* info =
2116     get_local_table_info(tab->m_internalName);
2117   delete tab;
2118   if (info == NULL)
2119     DBUG_RETURN(NULL);
2120   NdbTableImpl* bt = getBlobTable(*info->m_table_impl, col_no);
2121   DBUG_RETURN(bt);
2122 }
2123 
2124 bool
setTransporter(class Ndb * ndb,class TransporterFacade * tf)2125 NdbDictionaryImpl::setTransporter(class Ndb* ndb,
2126 				  class TransporterFacade * tf)
2127 {
2128   m_globalHash = tf->m_globalDictCache;
2129   if(m_receiver.setTransporter(ndb)){
2130     return true;
2131   }
2132   return false;
2133 }
2134 
2135 NdbTableImpl *
getIndexTable(NdbIndexImpl * index,NdbTableImpl * table)2136 NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index,
2137 				 NdbTableImpl * table)
2138 {
2139   const char *current_db= m_ndb.getDatabaseName();
2140   NdbTableImpl *index_table;
2141   const BaseString internalName(
2142     m_ndb.internalize_index_name(table, index->getName()));
2143   // Get index table in system database
2144   m_ndb.setDatabaseName(NDB_SYSTEM_DATABASE);
2145   index_table= getTable(m_ndb.externalizeTableName(internalName.c_str()));
2146   m_ndb.setDatabaseName(current_db);
2147   if (!index_table)
2148   {
2149     // Index table not found
2150     // Try geting index table in current database (old format)
2151     index_table= getTable(m_ndb.externalizeTableName(internalName.c_str()));
2152   }
2153   return index_table;
2154 }
2155 
2156 bool
setTransporter(class Ndb * ndb)2157 NdbDictInterface::setTransporter(class Ndb* ndb)
2158 {
2159   m_reference = ndb->getReference();
2160   m_impl = ndb->theImpl;
2161 
2162   return true;
2163 }
2164 
2165 TransporterFacade *
getTransporter() const2166 NdbDictInterface::getTransporter() const
2167 {
2168   return m_impl->m_transporter_facade;
2169 }
2170 
~NdbDictInterface()2171 NdbDictInterface::~NdbDictInterface()
2172 {
2173 }
2174 
2175 void
execSignal(void * dictImpl,const class NdbApiSignal * signal,const struct LinearSectionPtr ptr[3])2176 NdbDictInterface::execSignal(void* dictImpl,
2177 			     const class NdbApiSignal* signal,
2178 			     const struct LinearSectionPtr ptr[3])
2179 {
2180   NdbDictInterface * tmp = (NdbDictInterface*)dictImpl;
2181 
2182   const Uint32 gsn = signal->readSignalNumber();
2183   switch(gsn){
2184   case GSN_GET_TABINFOREF:
2185     tmp->execGET_TABINFO_REF(signal, ptr);
2186     break;
2187   case GSN_GET_TABINFO_CONF:
2188     tmp->execGET_TABINFO_CONF(signal, ptr);
2189     break;
2190   case GSN_CREATE_TABLE_REF:
2191     tmp->execCREATE_TABLE_REF(signal, ptr);
2192     break;
2193   case GSN_CREATE_TABLE_CONF:
2194     tmp->execCREATE_TABLE_CONF(signal, ptr);
2195     break;
2196   case GSN_DROP_TABLE_REF:
2197     tmp->execDROP_TABLE_REF(signal, ptr);
2198     break;
2199   case GSN_DROP_TABLE_CONF:
2200     tmp->execDROP_TABLE_CONF(signal, ptr);
2201     break;
2202   case GSN_ALTER_TABLE_REF:
2203     tmp->execALTER_TABLE_REF(signal, ptr);
2204     break;
2205   case GSN_ALTER_TABLE_CONF:
2206     tmp->execALTER_TABLE_CONF(signal, ptr);
2207     break;
2208   case GSN_CREATE_INDX_REF:
2209     tmp->execCREATE_INDX_REF(signal, ptr);
2210     break;
2211   case GSN_CREATE_INDX_CONF:
2212     tmp->execCREATE_INDX_CONF(signal, ptr);
2213     break;
2214   case GSN_DROP_INDX_REF:
2215     tmp->execDROP_INDX_REF(signal, ptr);
2216     break;
2217   case GSN_DROP_INDX_CONF:
2218     tmp->execDROP_INDX_CONF(signal, ptr);
2219     break;
2220   case GSN_INDEX_STAT_CONF:
2221     tmp->execINDEX_STAT_CONF(signal, ptr);
2222     break;
2223   case GSN_INDEX_STAT_REF:
2224     tmp->execINDEX_STAT_REF(signal, ptr);
2225     break;
2226   case GSN_CREATE_EVNT_REF:
2227     tmp->execCREATE_EVNT_REF(signal, ptr);
2228     break;
2229   case GSN_CREATE_EVNT_CONF:
2230     tmp->execCREATE_EVNT_CONF(signal, ptr);
2231     break;
2232   case GSN_SUB_START_CONF:
2233     tmp->execSUB_START_CONF(signal, ptr);
2234     break;
2235   case GSN_SUB_START_REF:
2236     tmp->execSUB_START_REF(signal, ptr);
2237     break;
2238   case GSN_SUB_STOP_CONF:
2239     tmp->execSUB_STOP_CONF(signal, ptr);
2240     break;
2241   case GSN_SUB_STOP_REF:
2242     tmp->execSUB_STOP_REF(signal, ptr);
2243     break;
2244   case GSN_DROP_EVNT_REF:
2245     tmp->execDROP_EVNT_REF(signal, ptr);
2246     break;
2247   case GSN_DROP_EVNT_CONF:
2248     tmp->execDROP_EVNT_CONF(signal, ptr);
2249     break;
2250   case GSN_LIST_TABLES_CONF:
2251     tmp->execLIST_TABLES_CONF(signal, ptr);
2252     break;
2253   case GSN_CREATE_FILEGROUP_REF:
2254     tmp->execCREATE_FILEGROUP_REF(signal, ptr);
2255     break;
2256   case GSN_CREATE_FILEGROUP_CONF:
2257     tmp->execCREATE_FILEGROUP_CONF(signal, ptr);
2258     break;
2259   case GSN_CREATE_FILE_REF:
2260     tmp->execCREATE_FILE_REF(signal, ptr);
2261     break;
2262   case GSN_CREATE_FILE_CONF:
2263     tmp->execCREATE_FILE_CONF(signal, ptr);
2264     break;
2265   case GSN_DROP_FILEGROUP_REF:
2266     tmp->execDROP_FILEGROUP_REF(signal, ptr);
2267     break;
2268   case GSN_DROP_FILEGROUP_CONF:
2269     tmp->execDROP_FILEGROUP_CONF(signal, ptr);
2270     break;
2271   case GSN_DROP_FILE_REF:
2272     tmp->execDROP_FILE_REF(signal, ptr);
2273     break;
2274   case GSN_DROP_FILE_CONF:
2275     tmp->execDROP_FILE_CONF(signal, ptr);
2276     break;
2277   case GSN_SCHEMA_TRANS_BEGIN_CONF:
2278     tmp->execSCHEMA_TRANS_BEGIN_CONF(signal, ptr);
2279     break;
2280   case GSN_SCHEMA_TRANS_BEGIN_REF:
2281     tmp->execSCHEMA_TRANS_BEGIN_REF(signal, ptr);
2282     break;
2283   case GSN_SCHEMA_TRANS_END_CONF:
2284     tmp->execSCHEMA_TRANS_END_CONF(signal, ptr);
2285     break;
2286   case GSN_SCHEMA_TRANS_END_REF:
2287     tmp->execSCHEMA_TRANS_END_REF(signal, ptr);
2288     break;
2289   case GSN_SCHEMA_TRANS_END_REP:
2290     tmp->execSCHEMA_TRANS_END_REP(signal, ptr);
2291     break;
2292   case GSN_WAIT_GCP_CONF:
2293     tmp->execWAIT_GCP_CONF(signal, ptr);
2294     break;
2295   case GSN_WAIT_GCP_REF:
2296     tmp->execWAIT_GCP_REF(signal, ptr);
2297     break;
2298   case GSN_CREATE_HASH_MAP_REF:
2299     tmp->execCREATE_HASH_MAP_REF(signal, ptr);
2300     break;
2301   case GSN_CREATE_HASH_MAP_CONF:
2302     tmp->execCREATE_HASH_MAP_CONF(signal, ptr);
2303     break;
2304   case GSN_CREATE_FK_REF:
2305     tmp->execCREATE_FK_REF(signal, ptr);
2306     break;
2307   case GSN_CREATE_FK_CONF:
2308     tmp->execCREATE_FK_CONF(signal, ptr);
2309     break;
2310 
2311   case GSN_DROP_FK_REF:
2312     tmp->execDROP_FK_REF(signal, ptr);
2313     break;
2314   case GSN_DROP_FK_CONF:
2315     tmp->execDROP_FK_CONF(signal, ptr);
2316     break;
2317 
2318   case GSN_NODE_FAILREP:
2319   {
2320     DBUG_ENTER("NdbDictInterface::NODE_FAILREP");
2321     const NodeFailRep *rep = CAST_CONSTPTR(NodeFailRep,
2322                                            signal->getDataPtr());
2323     Uint32 len = NodeFailRep::getNodeMaskLength(signal->getLength());
2324     assert(len == NodeBitmask::Size); // only full length in ndbapi
2325     for (Uint32 i = BitmaskImpl::find_first(len, rep->theAllNodes);
2326          i != BitmaskImpl::NotFound;
2327          i = BitmaskImpl::find_next(len, rep->theAllNodes, i + 1))
2328     {
2329       if (i <= MAX_DATA_NODE_ID)
2330       {
2331         // NdbDictInterface only cares about data-nodes (so far??)
2332         tmp->m_impl->theWaiter.nodeFail(i);
2333       }
2334     }
2335     DBUG_VOID_RETURN;
2336     break;
2337   }
2338   default:
2339     abort();
2340   }
2341 }
2342 
2343 void
execNodeStatus(void * dictImpl,Uint32 aNode,Uint32 ns_event)2344 NdbDictInterface::execNodeStatus(void* dictImpl, Uint32 aNode, Uint32 ns_event)
2345 {
2346 }
2347 
2348 int
dictSignal(NdbApiSignal * sig,LinearSectionPtr ptr[3],int secs,int node_specification,Uint32 wst,int timeout,Uint32 RETRIES,const int * errcodes,int temporaryMask)2349 NdbDictInterface::dictSignal(NdbApiSignal* sig,
2350 			     LinearSectionPtr ptr[3], int secs,
2351 			     int node_specification,
2352 			     Uint32 wst,
2353 			     int timeout, Uint32 RETRIES,
2354 			     const int *errcodes, int temporaryMask)
2355 {
2356   DBUG_ENTER("NdbDictInterface::dictSignal");
2357   DBUG_PRINT("enter", ("useMasterNodeId: %d", node_specification));
2358 
2359   int sleep = 50;
2360   int mod = 5;
2361 
2362   for(Uint32 i = 0; i<RETRIES; i++)
2363   {
2364     if (i > 0)
2365     {
2366       Uint32 t = sleep + 10 * (rand() % mod);
2367 #ifdef VM_TRACE
2368       ndbout_c("retry sleep %ums on error %u", t, m_error.code);
2369 #endif
2370       NdbSleep_MilliSleep(t);
2371     }
2372     if (i == RETRIES / 2)
2373     {
2374       mod = 10;
2375     }
2376     if (i == 3*RETRIES/4)
2377     {
2378       sleep = 100;
2379     }
2380 
2381     m_buffer.clear();
2382 
2383     // Protected area
2384     /*
2385       The PollGuard has an implicit call of unlock_and_signal through the
2386       ~PollGuard method. This method is called implicitly by the compiler
2387       in all places where the object is out of context due to a return,
2388       break, continue or simply end of statement block
2389     */
2390     PollGuard poll_guard(* m_impl);
2391     Uint32 node;
2392     switch(node_specification){
2393     case 0:
2394       node = (m_impl->get_node_alive(m_masterNodeId) ? m_masterNodeId :
2395 	      (m_masterNodeId = getTransporter()->get_an_alive_node()));
2396       break;
2397     case -1:
2398       node = getTransporter()->get_an_alive_node();
2399       break;
2400     default:
2401       node = node_specification;
2402     }
2403     DBUG_PRINT("info", ("node %d", node));
2404     if(node == 0){
2405       if (getTransporter()->is_cluster_completely_unavailable())
2406       {
2407         m_error.code= 4009;
2408       }
2409       else
2410       {
2411         m_error.code = 4035;
2412       }
2413       DBUG_RETURN(-1);
2414     }
2415     int res = (ptr ?
2416 	       m_impl->sendFragmentedSignal(sig, node, ptr, secs):
2417 	       m_impl->sendSignal(sig, node));
2418     if(res != 0){
2419       DBUG_PRINT("info", ("dictSignal failed to send signal"));
2420       m_error.code = 4007;
2421       continue;
2422     }
2423 
2424     m_impl->incClientStat(Ndb::WaitMetaRequestCount,1);
2425     m_error.code= 0;
2426     int ret_val= poll_guard.wait_n_unlock(timeout, node, wst, true);
2427     // End of Protected area
2428 
2429     if(ret_val == 0 && m_error.code == 0){
2430       // Normal return
2431       DBUG_RETURN(0);
2432     }
2433 
2434     /**
2435      * Handle error codes
2436      */
2437     if(ret_val == -2) //WAIT_NODE_FAILURE
2438     {
2439       m_error.code = 4013;
2440       continue;
2441     }
2442     if(m_impl->theWaiter.get_state() == WST_WAIT_TIMEOUT)
2443     {
2444       DBUG_PRINT("info", ("dictSignal caught time-out"));
2445       m_error.code = 4008;
2446       DBUG_RETURN(-1);
2447     }
2448 
2449     if ( temporaryMask == -1)
2450     {
2451       const NdbError &error= getNdbError();
2452       if (error.status ==  NdbError::TemporaryError)
2453       {
2454         continue;
2455       }
2456     }
2457     else if ( (temporaryMask & m_error.code) != 0 )
2458     {
2459       continue;
2460     }
2461     DBUG_PRINT("info", ("dictSignal caught error= %d", m_error.code));
2462 
2463     if(m_error.code && errcodes)
2464     {
2465       int j;
2466       for(j = 0; errcodes[j] ; j++){
2467 	if(m_error.code == errcodes[j]){
2468 	  break;
2469 	}
2470       }
2471       if(errcodes[j]) // Accepted error code
2472       {
2473         continue;
2474       }
2475     }
2476     break;
2477   }
2478   DBUG_RETURN(-1);
2479 }
2480 
2481 /*
2482   Get dictionary information for a table using table id as reference
2483 
2484   DESCRIPTION
2485     Sends a GET_TABINFOREQ signal containing the table id
2486  */
2487 NdbTableImpl *
getTable(int tableId,bool fullyQualifiedNames)2488 NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames)
2489 {
2490   NdbApiSignal tSignal(m_reference);
2491   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
2492 
2493   req->senderRef = m_reference;
2494   req->senderData = 0;
2495   req->requestType =
2496     GetTabInfoReq::RequestById | GetTabInfoReq::LongSignalConf;
2497   req->tableId = tableId;
2498   req->schemaTransId = m_tx.transId();
2499   tSignal.theReceiversBlockNumber = DBDICT;
2500   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
2501   tSignal.theLength = GetTabInfoReq::SignalLength;
2502 
2503   return getTable(&tSignal, 0, 0, fullyQualifiedNames);
2504 }
2505 
2506 /*
2507   Get dictionary information for a table using table name as the reference
2508 
2509   DESCRIPTION
2510     Send GET_TABINFOREQ signal with the table name in the first
2511     long section part
2512 */
2513 
2514 NdbTableImpl *
getTable(const BaseString & name,bool fullyQualifiedNames)2515 NdbDictInterface::getTable(const BaseString& name, bool fullyQualifiedNames)
2516 {
2517   NdbApiSignal tSignal(m_reference);
2518   GetTabInfoReq* const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
2519 
2520   const Uint32 namelen= name.length() + 1; // NULL terminated
2521   const Uint32 namelen_words= (namelen + 3) >> 2; // Size in words
2522 
2523   req->senderRef= m_reference;
2524   req->senderData= 0;
2525   req->requestType=
2526     GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
2527   req->tableNameLen= namelen;
2528   req->schemaTransId = m_tx.transId();
2529   tSignal.theReceiversBlockNumber= DBDICT;
2530   tSignal.theVerId_signalNumber= GSN_GET_TABINFOREQ;
2531   tSignal.theLength= GetTabInfoReq::SignalLength;
2532 
2533   // Copy name to m_buffer to get a word sized buffer
2534   m_buffer.clear();
2535   if (m_buffer.grow(namelen_words*4+4) ||
2536       m_buffer.append(name.c_str(), namelen))
2537   {
2538     m_error.code= 4000;
2539     return NULL;
2540   }
2541 
2542 #ifndef IGNORE_VALGRIND_WARNINGS
2543   Uint32 pad = 0;
2544   if (m_buffer.append(&pad, 4))
2545   {
2546     m_error.code= 4000;
2547     return NULL;
2548   }
2549 #endif
2550 
2551   LinearSectionPtr ptr[1];
2552   ptr[0].p= (Uint32*)m_buffer.get_data();
2553   ptr[0].sz= namelen_words;
2554 
2555   return getTable(&tSignal, ptr, 1, fullyQualifiedNames);
2556 }
2557 
2558 
2559 NdbTableImpl *
getTable(class NdbApiSignal * signal,LinearSectionPtr ptr[3],Uint32 noOfSections,bool fullyQualifiedNames)2560 NdbDictInterface::getTable(class NdbApiSignal * signal,
2561 			   LinearSectionPtr ptr[3],
2562 			   Uint32 noOfSections, bool fullyQualifiedNames)
2563 {
2564   int errCodes[] = {GetTabInfoRef::Busy, 0 };
2565   int timeout = DICT_WAITFOR_TIMEOUT;
2566   DBUG_EXECUTE_IF("ndb_timeout_gettabinforeq", {
2567     fprintf(stderr, "NdbDictInterface::getTable() times out in dictSignal WAIT_GET_TAB_INFO_REQ\n");
2568     timeout = 1000;
2569   });
2570 
2571   int r = dictSignal(signal, ptr, noOfSections,
2572 		     -1, // any node
2573 		     WAIT_GET_TAB_INFO_REQ,
2574                      timeout,  // parse stage
2575                      100,
2576                      errCodes);
2577 
2578   if (r)
2579     return 0;
2580 
2581   NdbTableImpl * rt = 0;
2582   m_error.code = parseTableInfo(&rt,
2583 				(Uint32*)m_buffer.get_data(),
2584   				m_buffer.length() / 4,
2585 				fullyQualifiedNames);
2586   if(rt)
2587   {
2588     if (rt->buildColumnHash())
2589     {
2590       m_error.code = 4000;
2591       delete rt;
2592       return NULL;
2593      }
2594 
2595     if (rt->m_fragmentType == NdbDictionary::Object::HashMapPartition)
2596     {
2597       NdbHashMapImpl tmp;
2598       if (get_hashmap(tmp, rt->m_hash_map_id))
2599       {
2600         delete rt;
2601         return NULL;
2602       }
2603       for (Uint32 i = 0; i<tmp.m_map.size(); i++)
2604       {
2605         assert(tmp.m_map[i] <= NDB_PARTITION_MASK);
2606         rt->m_hash_map.push_back(tmp.m_map[i]);
2607       }
2608     }
2609   }
2610 
2611   return rt;
2612 }
2613 
2614 void
execGET_TABINFO_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])2615 NdbDictInterface::execGET_TABINFO_CONF(const NdbApiSignal * signal,
2616 				       const LinearSectionPtr ptr[3])
2617 {
2618   const GetTabInfoConf* conf = CAST_CONSTPTR(GetTabInfoConf, signal->getDataPtr());
2619   const Uint32 i = GetTabInfoConf::DICT_TAB_INFO;
2620   if(signal->isFirstFragment()){
2621     m_fragmentId = signal->getFragmentId();
2622     if (m_buffer.grow(4 * conf->totalLen))
2623     {
2624       m_error.code= 4000;
2625       goto end;
2626     }
2627   } else {
2628     if(m_fragmentId != signal->getFragmentId()){
2629       abort();
2630     }
2631   }
2632 
2633   if (m_buffer.append(ptr[i].p, 4 * ptr[i].sz))
2634   {
2635     m_error.code= 4000;
2636   }
2637 end:
2638   if(!signal->isLastFragment()){
2639     return;
2640   }
2641 
2642   m_impl->theWaiter.signal(NO_WAIT);
2643 }
2644 
2645 void
execGET_TABINFO_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])2646 NdbDictInterface::execGET_TABINFO_REF(const NdbApiSignal * signal,
2647 				      const LinearSectionPtr ptr[3])
2648 {
2649   DBUG_ENTER("NdbDictInterface::execGET_TABINFO_REF");
2650   const GetTabInfoRef* ref = CAST_CONSTPTR(GetTabInfoRef,
2651 					   signal->getDataPtr());
2652 
2653   if (likely(signal->getLength() == GetTabInfoRef::SignalLength))
2654   {
2655     m_error.code= ref->errorCode;
2656   }
2657   else
2658   {
2659     /* 6.3 <-> 7.0 upgrade only */
2660     assert (signal->getLength() == GetTabInfoRef::OriginalSignalLength);
2661     m_error.code = (*(signal->getDataPtr() +
2662                       GetTabInfoRef::OriginalErrorOffset));
2663   }
2664   DBUG_PRINT("info", ("Error code = %d", m_error.code));
2665   m_impl->theWaiter.signal(NO_WAIT);
2666   DBUG_VOID_RETURN;
2667 }
2668 
2669 /*****************************************************************
2670  * Pack/Unpack tables
2671  */
2672 struct ApiKernelMapping {
2673   Int32 kernelConstant;
2674   Int32 apiConstant;
2675 };
2676 
2677 Uint32
getApiConstant(Int32 kernelConstant,const ApiKernelMapping map[],Uint32 def)2678 getApiConstant(Int32 kernelConstant, const ApiKernelMapping map[], Uint32 def)
2679 {
2680   int i = 0;
2681   while(map[i].kernelConstant != kernelConstant){
2682     if(map[i].kernelConstant == -1 &&
2683        map[i].apiConstant == -1){
2684       return def;
2685     }
2686     i++;
2687   }
2688   return map[i].apiConstant;
2689 }
2690 
2691 Uint32
getKernelConstant(Int32 apiConstant,const ApiKernelMapping map[],Uint32 def)2692 getKernelConstant(Int32 apiConstant, const ApiKernelMapping map[], Uint32 def)
2693 {
2694   int i = 0;
2695   while(map[i].apiConstant != apiConstant){
2696     if(map[i].kernelConstant == -1 &&
2697        map[i].apiConstant == -1){
2698       return def;
2699     }
2700     i++;
2701   }
2702   return map[i].kernelConstant;
2703 }
2704 
2705 static const
2706 ApiKernelMapping
2707 fragmentTypeMapping[] = {
2708   { DictTabInfo::AllNodesSmallTable,  NdbDictionary::Object::FragAllSmall },
2709   { DictTabInfo::AllNodesMediumTable, NdbDictionary::Object::FragAllMedium },
2710   { DictTabInfo::AllNodesLargeTable,  NdbDictionary::Object::FragAllLarge },
2711   { DictTabInfo::SingleFragment,      NdbDictionary::Object::FragSingle },
2712   { DictTabInfo::DistrKeyHash,      NdbDictionary::Object::DistrKeyHash },
2713   { DictTabInfo::DistrKeyLin,      NdbDictionary::Object::DistrKeyLin },
2714   { DictTabInfo::UserDefined,      NdbDictionary::Object::UserDefined },
2715   { DictTabInfo::HashMapPartition, NdbDictionary::Object::HashMapPartition },
2716   { -1, -1 }
2717 };
2718 
2719 static const
2720 ApiKernelMapping
2721 objectTypeMapping[] = {
2722   { DictTabInfo::SystemTable,        NdbDictionary::Object::SystemTable },
2723   { DictTabInfo::UserTable,          NdbDictionary::Object::UserTable },
2724   { DictTabInfo::UniqueHashIndex,    NdbDictionary::Object::UniqueHashIndex },
2725   { DictTabInfo::OrderedIndex,       NdbDictionary::Object::OrderedIndex },
2726   { DictTabInfo::HashIndexTrigger,   NdbDictionary::Object::HashIndexTrigger },
2727   { DictTabInfo::IndexTrigger,       NdbDictionary::Object::IndexTrigger },
2728   { DictTabInfo::SubscriptionTrigger,NdbDictionary::Object::SubscriptionTrigger },
2729   { DictTabInfo::ReadOnlyConstraint ,NdbDictionary::Object::ReadOnlyConstraint },
2730   { DictTabInfo::Tablespace,         NdbDictionary::Object::Tablespace },
2731   { DictTabInfo::LogfileGroup,       NdbDictionary::Object::LogfileGroup },
2732   { DictTabInfo::Datafile,           NdbDictionary::Object::Datafile },
2733   { DictTabInfo::Undofile,           NdbDictionary::Object::Undofile },
2734   { DictTabInfo::ReorgTrigger,       NdbDictionary::Object::ReorgTrigger },
2735 
2736   { DictTabInfo::ForeignKey,         NdbDictionary::Object::ForeignKey },
2737   { DictTabInfo::FKParentTrigger,    NdbDictionary::Object::FKParentTrigger },
2738   { DictTabInfo::FKChildTrigger,     NdbDictionary::Object::FKChildTrigger },
2739   { -1, -1 }
2740 };
2741 
2742 static const
2743 ApiKernelMapping
2744 objectStateMapping[] = {
2745   { DictTabInfo::StateOffline,       NdbDictionary::Object::StateOffline },
2746   { DictTabInfo::StateBuilding,      NdbDictionary::Object::StateBuilding },
2747   { DictTabInfo::StateDropping,      NdbDictionary::Object::StateDropping },
2748   { DictTabInfo::StateOnline,        NdbDictionary::Object::StateOnline },
2749   { DictTabInfo::StateBackup,        NdbDictionary::Object::StateBackup },
2750   { DictTabInfo::StateBroken,        NdbDictionary::Object::StateBroken },
2751   { -1, -1 }
2752 };
2753 
2754 static const
2755 ApiKernelMapping
2756 objectStoreMapping[] = {
2757   { DictTabInfo::StoreNotLogged,     NdbDictionary::Object::StoreNotLogged },
2758   { DictTabInfo::StorePermanent,     NdbDictionary::Object::StorePermanent },
2759   { -1, -1 }
2760 };
2761 
2762 static const
2763 ApiKernelMapping
2764 indexTypeMapping[] = {
2765   { DictTabInfo::UniqueHashIndex,    NdbDictionary::Index::UniqueHashIndex },
2766   { DictTabInfo::OrderedIndex,       NdbDictionary::Index::OrderedIndex },
2767   { -1, -1 }
2768 };
2769 
2770 int
parseTableInfo(NdbTableImpl ** ret,const Uint32 * data,Uint32 len,bool fullyQualifiedNames,Uint32 version)2771 NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
2772 				 const Uint32 * data, Uint32 len,
2773 				 bool fullyQualifiedNames,
2774                                  Uint32 version)
2775 {
2776   SimplePropertiesLinearReader it(data, len);
2777   DictTabInfo::Table *tableDesc;
2778   SimpleProperties::UnpackStatus s;
2779   DBUG_ENTER("NdbDictInterface::parseTableInfo");
2780 
2781   tableDesc = (DictTabInfo::Table*)NdbMem_Allocate(sizeof(DictTabInfo::Table));
2782   if (!tableDesc)
2783   {
2784     DBUG_RETURN(4000);
2785   }
2786   tableDesc->init();
2787   s = SimpleProperties::unpack(it, tableDesc,
2788 			       DictTabInfo::TableMapping,
2789 			       DictTabInfo::TableMappingSize,
2790 			       true, true);
2791 
2792   if(s != SimpleProperties::Break){
2793     NdbMem_Free((void*)tableDesc);
2794     DBUG_RETURN(703);
2795   }
2796   const char * internalName = tableDesc->TableName;
2797   const char * externalName = Ndb::externalizeTableName(internalName, fullyQualifiedNames);
2798 
2799   NdbTableImpl * impl = new NdbTableImpl();
2800   impl->m_id = tableDesc->TableId;
2801   impl->m_version = tableDesc->TableVersion;
2802   impl->m_status = NdbDictionary::Object::Retrieved;
2803   if (!impl->m_internalName.assign(internalName) ||
2804       impl->updateMysqlName() ||
2805       !impl->m_externalName.assign(externalName) ||
2806       impl->m_frm.assign(tableDesc->FrmData, tableDesc->FrmLen) ||
2807       impl->m_range.assign((Int32*)tableDesc->RangeListData,
2808                            /* yuck */tableDesc->RangeListDataLen / 4))
2809   {
2810     DBUG_RETURN(4000);
2811   }
2812 
2813   {
2814     /**
2815      * NOTE: fragment data is currently an array of Uint16
2816      *       and len is specified in bytes (yuck)
2817      *       please change to Uint32 and len == count
2818      */
2819     Uint32 cnt = tableDesc->FragmentDataLen / 2;
2820     for (Uint32 i = 0; i<cnt; i++)
2821       if (impl->m_fd.push_back((Uint32)tableDesc->FragmentData[i]))
2822         DBUG_RETURN(4000);
2823   }
2824 
2825   impl->m_fragmentCount = tableDesc->FragmentCount;
2826 
2827   /*
2828     We specifically don't get tablespace data and range/list arrays here
2829     since those are known by the MySQL Server through analysing the
2830     frm file.
2831     Fragment Data contains the real node group mapping and the fragment
2832     identities used for each fragment. At the moment we have no need for
2833     this.
2834     Frm file is needed for autodiscovery.
2835   */
2836 
2837   impl->m_fragmentType = (NdbDictionary::Object::FragmentType)
2838     getApiConstant(tableDesc->FragmentType,
2839 		   fragmentTypeMapping,
2840 		   (Uint32)NdbDictionary::Object::FragUndefined);
2841 
2842   if (impl->m_fragmentType == NdbDictionary::Object::HashMapPartition)
2843   {
2844     impl->m_hash_map_id = tableDesc->HashMapObjectId;
2845     impl->m_hash_map_version = tableDesc->HashMapVersion;
2846   }
2847   else
2848   {
2849     impl->m_hash_map_id = ~0;
2850     impl->m_hash_map_version = ~0;
2851   }
2852 
2853   Uint64 max_rows = ((Uint64)tableDesc->MaxRowsHigh) << 32;
2854   max_rows += tableDesc->MaxRowsLow;
2855   impl->m_max_rows = max_rows;
2856   Uint64 min_rows = ((Uint64)tableDesc->MinRowsHigh) << 32;
2857   min_rows += tableDesc->MinRowsLow;
2858   impl->m_min_rows = min_rows;
2859   impl->m_default_no_part_flag = tableDesc->DefaultNoPartFlag;
2860   impl->m_linear_flag = tableDesc->LinearHashFlag;
2861   impl->m_logging = tableDesc->TableLoggedFlag;
2862   impl->m_temporary = tableDesc->TableTemporaryFlag;
2863   impl->m_row_gci = tableDesc->RowGCIFlag;
2864   impl->m_row_checksum = tableDesc->RowChecksumFlag;
2865   impl->m_force_var_part = tableDesc->ForceVarPartFlag;
2866   impl->m_kvalue = tableDesc->TableKValue;
2867   impl->m_minLoadFactor = tableDesc->MinLoadFactor;
2868   impl->m_maxLoadFactor = tableDesc->MaxLoadFactor;
2869   impl->m_single_user_mode = tableDesc->SingleUserMode;
2870   impl->m_storageType = tableDesc->TableStorageType;
2871   impl->m_extra_row_gci_bits = tableDesc->ExtraRowGCIBits;
2872   impl->m_extra_row_author_bits = tableDesc->ExtraRowAuthorBits;
2873 
2874   impl->m_indexType = (NdbDictionary::Object::Type)
2875     getApiConstant(tableDesc->TableType,
2876 		   indexTypeMapping,
2877 		   NdbDictionary::Object::TypeUndefined);
2878 
2879   bool columnsIndexSourced= false;
2880 
2881   if(impl->m_indexType == NdbDictionary::Object::TypeUndefined){
2882   } else {
2883     const char * externalPrimary =
2884       Ndb::externalizeTableName(tableDesc->PrimaryTable, fullyQualifiedNames);
2885     if (!impl->m_primaryTable.assign(externalPrimary))
2886     {
2887       DBUG_RETURN(4000);
2888     }
2889     columnsIndexSourced= true;
2890   }
2891 
2892   Uint32 i;
2893   for(i = 0; i < tableDesc->NoOfAttributes; i++) {
2894     DictTabInfo::Attribute attrDesc; attrDesc.init();
2895     s = SimpleProperties::unpack(it,
2896 				 &attrDesc,
2897 				 DictTabInfo::AttributeMapping,
2898 				 DictTabInfo::AttributeMappingSize,
2899 				 true, true);
2900     if(s != SimpleProperties::Break){
2901       delete impl;
2902       NdbMem_Free((void*)tableDesc);
2903       DBUG_RETURN(703);
2904     }
2905 
2906     NdbColumnImpl * col = new NdbColumnImpl();
2907     col->m_attrId = attrDesc.AttributeId;
2908     col->setName(attrDesc.AttributeName);
2909 
2910     // check type and compute attribute size and array size
2911     if (! attrDesc.translateExtType()) {
2912       delete col;
2913       delete impl;
2914       NdbMem_Free((void*)tableDesc);
2915       DBUG_RETURN(703);
2916     }
2917     col->m_type = (NdbDictionary::Column::Type)attrDesc.AttributeExtType;
2918     col->m_precision = (attrDesc.AttributeExtPrecision & 0xFFFF);
2919     col->m_scale = attrDesc.AttributeExtScale;
2920     col->m_length = attrDesc.AttributeExtLength;
2921     // charset in upper half of precision
2922     unsigned cs_number = (attrDesc.AttributeExtPrecision >> 16);
2923     // charset is defined exactly for char types
2924     if (col->getCharType() != (cs_number != 0)) {
2925       delete col;
2926       delete impl;
2927       NdbMem_Free((void*)tableDesc);
2928       DBUG_RETURN(703);
2929     }
2930     if (col->getCharType()) {
2931       col->m_cs = get_charset(cs_number, MYF(0));
2932       if (col->m_cs == NULL) {
2933         delete col;
2934         delete impl;
2935         NdbMem_Free((void*)tableDesc);
2936         DBUG_RETURN(743);
2937       }
2938     }
2939     col->m_orgAttrSize = attrDesc.AttributeSize;
2940     col->m_attrSize = (1 << attrDesc.AttributeSize) / 8;
2941     col->m_arraySize = attrDesc.AttributeArraySize;
2942     col->m_arrayType = attrDesc.AttributeArrayType;
2943     if(attrDesc.AttributeSize == 0)
2944     {
2945       col->m_attrSize = 4;
2946       col->m_arraySize = (attrDesc.AttributeArraySize + 31) >> 5;
2947     }
2948     col->m_storageType = attrDesc.AttributeStorageType;
2949     col->m_dynamic = (attrDesc.AttributeDynamic != 0);
2950     col->m_indexSourced= columnsIndexSourced;
2951 
2952     if (col->getBlobType()) {
2953       if (unlikely(col->m_arrayType) == NDB_ARRAYTYPE_FIXED)
2954         col->m_blobVersion = NDB_BLOB_V1;
2955       else if (col->m_arrayType == NDB_ARRAYTYPE_MEDIUM_VAR)
2956         col->m_blobVersion = NDB_BLOB_V2;
2957       else {
2958         delete impl;
2959         NdbMem_Free((void*)tableDesc);
2960         DBUG_RETURN(4263);
2961       }
2962     }
2963 
2964     col->m_pk = attrDesc.AttributeKeyFlag;
2965     col->m_distributionKey = (attrDesc.AttributeDKey != 0);
2966     col->m_nullable = attrDesc.AttributeNullableFlag;
2967     col->m_autoIncrement = (attrDesc.AttributeAutoIncrement != 0);
2968     col->m_autoIncrementInitialValue = ~0;
2969 
2970     if (attrDesc.AttributeDefaultValueLen)
2971     {
2972       assert(attrDesc.AttributeDefaultValueLen >= sizeof(Uint32)); /* AttributeHeader */
2973       const char* defPtr = (const char*) attrDesc.AttributeDefaultValue;
2974       Uint32 a = * (const Uint32*) defPtr;
2975       AttributeHeader ah(ntohl(a));
2976       Uint32 bytesize = ah.getByteSize();
2977       assert(attrDesc.AttributeDefaultValueLen >= sizeof(Uint32) + bytesize);
2978 
2979       if (bytesize)
2980       {
2981         if (col->m_defaultValue.assign(defPtr + sizeof(Uint32), bytesize))
2982         {
2983           delete col;
2984           delete impl;
2985           DBUG_RETURN(4000);
2986         }
2987 
2988         /* Table meta-info is normally stored in network byte order by
2989          * SimpleProperties
2990          * For the default value 'Blob' we do the work
2991          */
2992         /* In-place convert network -> host */
2993         NdbSqlUtil::convertByteOrder(attrDesc.AttributeExtType,
2994                                      attrDesc.AttributeSize,
2995                                      attrDesc.AttributeArrayType,
2996                                      attrDesc.AttributeArraySize,
2997                                      (uchar*) col->m_defaultValue.get_data(),
2998                                      bytesize);
2999 
3000         impl->m_has_default_values = true;
3001       }
3002     }
3003 
3004     col->m_column_no = impl->m_columns.size();
3005     impl->m_columns.push_back(col);
3006     it.next();
3007   }
3008 
3009   impl->computeAggregates();
3010 
3011   if(tableDesc->ReplicaDataLen > 0)
3012   {
3013     Uint16 replicaCount = ntohs(tableDesc->ReplicaData[0]);
3014     Uint16 fragCount = ntohs(tableDesc->ReplicaData[1]);
3015 
3016     assert(replicaCount <= 256);
3017 
3018     impl->m_replicaCount = (Uint8)replicaCount;
3019     impl->m_fragmentCount = fragCount;
3020     DBUG_PRINT("info", ("replicaCount=%x , fragCount=%x",replicaCount,fragCount));
3021     Uint32 pos = 2;
3022     for(i = 0; i < (Uint32) fragCount;i++)
3023     {
3024       pos++; // skip logpart
3025       for (Uint32 j = 0; j<(Uint32)replicaCount; j++)
3026       {
3027 	if (impl->m_fragments.push_back(ntohs(tableDesc->ReplicaData[pos++])))
3028 	{
3029           delete impl;
3030           DBUG_RETURN(4000);
3031         }
3032       }
3033     }
3034 
3035     Uint32 topBit = (1 << 31);
3036     for(; topBit && !(fragCount & topBit); ){
3037       topBit >>= 1;
3038     }
3039     impl->m_hashValueMask = topBit - 1;
3040     impl->m_hashpointerValue = fragCount - (impl->m_hashValueMask + 1);
3041   }
3042   else
3043   {
3044     impl->m_fragmentCount = tableDesc->FragmentCount;
3045     impl->m_replicaCount = 0;
3046     impl->m_hashValueMask = 0;
3047     impl->m_hashpointerValue = 0;
3048   }
3049 
3050   impl->m_tablespace_id = tableDesc->TablespaceId;
3051   impl->m_tablespace_version = tableDesc->TablespaceVersion;
3052 
3053   * ret = impl;
3054 
3055   NdbMem_Free((void*)tableDesc);
3056   if (version < MAKE_VERSION(5,1,3))
3057   {
3058     ;
3059   }
3060   else
3061   {
3062     assert(impl->m_fragmentCount > 0);
3063   }
3064   DBUG_RETURN(0);
3065 }
3066 
3067 /*****************************************************************
3068  * Create table and alter table
3069  */
3070 int
createTable(NdbTableImpl & t,NdbDictObjectImpl & objid)3071 NdbDictionaryImpl::createTable(NdbTableImpl &t, NdbDictObjectImpl & objid)
3072 {
3073   DBUG_ENTER("NdbDictionaryImpl::createTable");
3074 
3075   bool autoIncrement = false;
3076   Uint64 initialValue = 0;
3077   for (Uint32 i = 0; i < t.m_columns.size(); i++) {
3078     const NdbColumnImpl* c = t.m_columns[i];
3079     assert(c != NULL);
3080     if (c->m_autoIncrement) {
3081       if (autoIncrement) {
3082         m_error.code = 4335;
3083         DBUG_RETURN(-1);
3084       }
3085       autoIncrement = true;
3086       initialValue = c->m_autoIncrementInitialValue;
3087     }
3088 
3089     if (c->m_pk && (! c->m_defaultValue.empty())) {
3090       /* Default value for primary key column not supported */
3091       m_error.code = 792;
3092       DBUG_RETURN(-1);
3093     }
3094   }
3095 
3096   // create table
3097   if (m_receiver.createTable(m_ndb, t) != 0)
3098     DBUG_RETURN(-1);
3099   Uint32* data = (Uint32*)m_receiver.m_buffer.get_data();
3100   t.m_id = data[0];
3101   t.m_version = data[1];
3102   objid.m_id = data[0];
3103   objid.m_version = data[1];
3104 
3105   // update table def from DICT - by-pass cache
3106   NdbTableImpl* t2 =
3107     m_receiver.getTable(t.m_internalName, m_ndb.usingFullyQualifiedNames());
3108 
3109   // check if we got back same table
3110   if (t2 == NULL) {
3111     DBUG_PRINT("info", ("table %s dropped by another thread",
3112                         t.m_internalName.c_str()));
3113     m_error.code = 283;
3114     DBUG_RETURN(-1);
3115   }
3116   if (t.m_id != t2->m_id || t.m_version != t2->m_version) {
3117     DBUG_PRINT("info", ("table %s re-created by another thread",
3118                         t.m_internalName.c_str()));
3119     m_error.code = 283;
3120     delete t2;
3121     DBUG_RETURN(-1);
3122   }
3123 
3124   // auto-increment - use "t" because initial value is not in DICT
3125   {
3126     if (autoIncrement) {
3127       // XXX unlikely race condition - t.m_id may no longer be same table
3128       // the tuple id range is not used on input
3129       Ndb::TupleIdRange range;
3130       if (m_ndb.setTupleIdInNdb(&t, range, initialValue, false) == -1) {
3131         assert(m_ndb.theError.code != 0);
3132         m_error.code = m_ndb.theError.code;
3133         delete t2;
3134         DBUG_RETURN(-1);
3135       }
3136     }
3137   }
3138 
3139   // blob tables - use "t2" to get values set by kernel
3140   if (t.m_noOfBlobs != 0) {
3141 
3142     // fix up disk data in t2 columns
3143     Uint32 i;
3144     for (i = 0; i < t.m_columns.size(); i++) {
3145       const NdbColumnImpl* c = t.m_columns[i];
3146       NdbColumnImpl* c2 = t2->m_columns[i];
3147       if (c->getBlobType()) {
3148         // type was mangled before sending to DICT
3149         assert(c2->m_storageType == NDB_STORAGETYPE_MEMORY);
3150         c2->m_storageType = c->m_storageType;
3151       }
3152     }
3153 
3154     if (createBlobTables(*t2) != 0) {
3155       int save_code = m_error.code;
3156       (void)dropTableGlobal(*t2);
3157       m_error.code = save_code;
3158       delete t2;
3159       DBUG_RETURN(-1);
3160     }
3161   }
3162 
3163   // not entered in cache
3164   delete t2;
3165   DBUG_RETURN(0);
3166 }
3167 
3168 int
optimizeTable(const NdbTableImpl & t,NdbOptimizeTableHandleImpl & h)3169 NdbDictionaryImpl::optimizeTable(const NdbTableImpl &t,
3170                                  NdbOptimizeTableHandleImpl &h)
3171 {
3172   DBUG_ENTER("NdbDictionaryImpl::optimizeTableGlobal(const NdbTableImpl)");
3173   DBUG_RETURN(h.init(&m_ndb, t));
3174 }
3175 
3176 int
optimizeIndex(const NdbIndexImpl & index,NdbOptimizeIndexHandleImpl & h)3177 NdbDictionaryImpl::optimizeIndex(const NdbIndexImpl &index,
3178                                  NdbOptimizeIndexHandleImpl &h)
3179 {
3180   DBUG_ENTER("NdbDictionaryImpl::optimizeIndexGlobal(const NdbIndexImpl)");
3181   DBUG_RETURN(h.init(&m_ndb, index));
3182 }
3183 
3184 int
createBlobTables(const NdbTableImpl & t)3185 NdbDictionaryImpl::createBlobTables(const NdbTableImpl& t)
3186 {
3187   DBUG_ENTER("NdbDictionaryImpl::createBlobTables");
3188   for (unsigned i = 0; i < t.m_columns.size(); i++) {
3189     const NdbColumnImpl & c = *t.m_columns[i];
3190     if (! c.getBlobType() || c.getPartSize() == 0)
3191       continue;
3192     DBUG_PRINT("info", ("col: %s array type: %u storage type: %u",
3193                         c.m_name.c_str(), c.m_arrayType, c.m_storageType));
3194     NdbTableImpl bt;
3195     NdbError error;
3196     if (NdbBlob::getBlobTable(bt, &t, &c, error) == -1) {
3197       m_error.code = error.code;
3198       DBUG_RETURN(-1);
3199     }
3200     NdbDictionary::Column::StorageType
3201       d = NdbDictionary::Column::StorageTypeDisk;
3202     if (t.m_columns[i]->getStorageType() == d) {
3203       const char* colName = c.m_blobVersion == 1 ? "DATA" : "NDB$DATA";
3204       NdbColumnImpl* bc = bt.getColumn(colName);
3205       assert(bc != NULL);
3206       bc->setStorageType(d);
3207     }
3208     NdbDictionary::ObjectId objId; // ignore objid
3209     if (createTable(bt, NdbDictObjectImpl::getImpl(objId)) != 0) {
3210       DBUG_RETURN(-1);
3211     }
3212   }
3213   DBUG_RETURN(0);
3214 }
3215 
3216 int
createTable(Ndb & ndb,NdbTableImpl & impl)3217 NdbDictInterface::createTable(Ndb & ndb,
3218 			      NdbTableImpl & impl)
3219 {
3220   int ret;
3221 
3222   DBUG_ENTER("NdbDictInterface::createTable");
3223 
3224   if (impl.m_fragmentType == NdbDictionary::Object::HashMapPartition)
3225   {
3226     if (impl.m_hash_map_id == RNIL && impl.m_hash_map_version == ~(Uint32)0)
3227     {
3228       /**
3229        * Make sure that hashmap exists (i.e after upgrade or similar)
3230        */
3231       NdbHashMapImpl hashmap;
3232       ret = create_hashmap(hashmap, 0,
3233                            CreateHashMapReq::CreateDefault |
3234                            CreateHashMapReq::CreateIfNotExists);
3235       if (ret)
3236       {
3237         DBUG_RETURN(ret);
3238       }
3239     }
3240   }
3241 
3242   syncInternalName(ndb, impl);
3243 
3244   UtilBufferWriter w(m_buffer);
3245   ret= serializeTableDesc(ndb, impl, w);
3246   if(ret != 0)
3247   {
3248     DBUG_RETURN(ret);
3249   }
3250 
3251   DBUG_RETURN(sendCreateTable(impl, w));
3252 }
3253 
supportedAlterTable(NdbTableImpl & old_impl,NdbTableImpl & impl)3254 bool NdbDictionaryImpl::supportedAlterTable(NdbTableImpl &old_impl,
3255 					    NdbTableImpl &impl)
3256 {
3257   return m_receiver.supportedAlterTable(old_impl, impl);
3258 }
3259 
supportedAlterTable(const NdbTableImpl & old_impl,NdbTableImpl & impl)3260 bool NdbDictInterface::supportedAlterTable(const NdbTableImpl &old_impl,
3261 					   NdbTableImpl &impl)
3262 {
3263   Uint32 change_mask;
3264   return (compChangeMask(old_impl, impl, change_mask) == 0);
3265 }
3266 
alterTable(NdbTableImpl & old_impl,NdbTableImpl & impl)3267 int NdbDictionaryImpl::alterTable(NdbTableImpl &old_impl,
3268                                   NdbTableImpl &impl)
3269 {
3270   return alterTableGlobal(old_impl, impl);
3271 }
3272 
alterTableGlobal(NdbTableImpl & old_impl,NdbTableImpl & impl)3273 int NdbDictionaryImpl::alterTableGlobal(NdbTableImpl &old_impl,
3274                                         NdbTableImpl &impl)
3275 {
3276   DBUG_ENTER("NdbDictionaryImpl::alterTableGlobal");
3277   // Alter the table
3278   Uint32 changeMask = 0;
3279   int ret = m_receiver.alterTable(m_ndb, old_impl, impl, changeMask);
3280 #if ndb_bug41905
3281   old_impl.m_status = NdbDictionary::Object::Invalid;
3282 #endif
3283   if(ret == 0){
3284     NdbDictInterface::Tx::Op op;
3285     op.m_gsn = GSN_ALTER_TABLE_REQ;
3286     op.m_impl = &old_impl;
3287     if (m_tx.m_op.push_back(op) == -1) {
3288       m_error.code = 4000;
3289       DBUG_RETURN(-1);
3290     }
3291     m_globalHash->lock();
3292     ret = m_globalHash->inc_ref_count(op.m_impl);
3293     m_globalHash->unlock();
3294     if (ret != 0)
3295       m_error.code = 723;
3296 
3297     if (ret == 0)
3298     {
3299       if (alterBlobTables(old_impl, impl, changeMask) != 0)
3300       {
3301         DBUG_RETURN(-1);
3302       }
3303     }
3304     DBUG_RETURN(ret);
3305   }
3306   ERR_RETURN(getNdbError(), ret);
3307 }
3308 
3309 int
alterBlobTables(const NdbTableImpl & old_tab,const NdbTableImpl & new_tab,Uint32 tabChangeMask)3310 NdbDictionaryImpl::alterBlobTables(const NdbTableImpl & old_tab,
3311                                    const NdbTableImpl & new_tab,
3312                                    Uint32 tabChangeMask)
3313 {
3314   DBUG_ENTER("NdbDictionaryImpl::alterBlobTables");
3315   if (old_tab.m_noOfBlobs == 0)
3316     DBUG_RETURN(0);
3317 
3318   char db[MAX_TAB_NAME_SIZE];
3319   char schema[MAX_TAB_NAME_SIZE];
3320   new_tab.getDbName(db, sizeof(db));
3321   new_tab.getSchemaName(schema, sizeof(schema));
3322 
3323   bool name_change = false;
3324   if (AlterTableReq::getNameFlag(tabChangeMask))
3325   {
3326     char old_db[MAX_TAB_NAME_SIZE];
3327     char old_schema[MAX_TAB_NAME_SIZE];
3328     if (old_tab.getDbName(old_db, sizeof(old_db)) != 0)
3329     {
3330       m_error.code = 705;
3331       DBUG_RETURN(-1);
3332     }
3333     if (old_tab.getSchemaName(old_schema, sizeof(old_schema)) != 0)
3334     {
3335       m_error.code = 705;
3336       DBUG_RETURN(-1);
3337     }
3338     bool db_change = strcmp(old_db, db) != 0;
3339     bool schema_change = strcmp(old_schema, schema) != 0;
3340     name_change = db_change || schema_change;
3341    }
3342 
3343   bool tab_frag_change = AlterTableReq::getAddFragFlag(tabChangeMask) != 0;
3344 
3345   for (unsigned i = 0; i < old_tab.m_columns.size(); i++)
3346   {
3347     NdbColumnImpl & c = *old_tab.m_columns[i];
3348     if (! c.getBlobType() || c.getPartSize() == 0)
3349       continue;
3350     NdbTableImpl* _bt = c.m_blobTable;
3351     if (_bt == NULL)
3352     {
3353       continue; // "force" mode on
3354     }
3355 
3356     NdbDictionary::Table& bt = * _bt->m_facade;
3357     NdbDictionary::Table new_bt(bt);
3358 
3359     if (name_change)
3360     {
3361       new_bt.m_impl.setDbSchema(db, schema);
3362     }
3363 
3364     bool frag_change = false;
3365     if (tab_frag_change)
3366     {
3367       frag_change =
3368         new_bt.getFragmentType() == old_tab.getFragmentType() &&
3369         new_bt.getFragmentCount() == old_tab.getFragmentCount() &&
3370         new_bt.getFragmentCount() != new_tab.getFragmentCount();
3371 
3372     }
3373     if (frag_change)
3374     {
3375       new_bt.setFragmentType(new_tab.getFragmentType());
3376       new_bt.setDefaultNoPartitionsFlag(new_tab.getDefaultNoPartitionsFlag());
3377       new_bt.setFragmentCount(new_tab.getFragmentCount());
3378       new_bt.setFragmentData(new_tab.getFragmentData(), new_tab.getFragmentDataLen());
3379       NdbDictionary::HashMap hm;
3380       if (getHashMap(hm, &new_tab) != -1)
3381       {
3382         new_bt.setHashMap(hm);
3383       }
3384     }
3385 
3386     Uint32 changeMask = 0;
3387     if (name_change || frag_change)
3388     {
3389       int ret = m_receiver.alterTable(m_ndb, bt.m_impl, new_bt.m_impl, changeMask);
3390       if (ret != 0)
3391       {
3392         DBUG_RETURN(ret);
3393       }
3394       assert(!name_change || AlterTableReq::getNameFlag(changeMask));
3395       assert(!frag_change || AlterTableReq::getAddFragFlag(changeMask));
3396     }
3397   }
3398   DBUG_RETURN(0);
3399 }
3400 
3401 int
alterTable(Ndb & ndb,const NdbTableImpl & old_impl,NdbTableImpl & impl,Uint32 & change_mask)3402 NdbDictInterface::alterTable(Ndb & ndb,
3403                              const NdbTableImpl &old_impl,
3404                              NdbTableImpl &impl,
3405                              Uint32 & change_mask)
3406 {
3407   int ret;
3408 
3409   DBUG_ENTER("NdbDictInterface::alterTable");
3410 
3411   syncInternalName(ndb, impl);
3412 
3413   /* Check that alter request is valid and compute stuff to alter. */
3414   ret= compChangeMask(old_impl, impl, change_mask);
3415   if(ret != 0)
3416     DBUG_RETURN(ret);
3417 
3418   UtilBufferWriter w(m_buffer);
3419   ret= serializeTableDesc(ndb, impl, w);
3420   if(ret != 0)
3421     DBUG_RETURN(ret);
3422 
3423   DBUG_RETURN(sendAlterTable(impl, change_mask, w));
3424 }
3425 
3426 void
syncInternalName(Ndb & ndb,NdbTableImpl & impl)3427 NdbDictInterface::syncInternalName(Ndb & ndb, NdbTableImpl &impl)
3428 {
3429   const BaseString internalName(
3430     ndb.internalize_table_name(impl.m_externalName.c_str()));
3431   impl.m_internalName.assign(internalName);
3432   impl.updateMysqlName();
3433 }
3434 
3435 /*
3436   Compare old and new Table descriptors.
3437   Set the corresponding flag for any (supported) difference.
3438   Error on any difference not supported for alter table.
3439 */
3440 int
compChangeMask(const NdbTableImpl & old_impl,const NdbTableImpl & impl,Uint32 & change_mask)3441 NdbDictInterface::compChangeMask(const NdbTableImpl &old_impl,
3442                                  const NdbTableImpl &impl,
3443                                  Uint32 &change_mask)
3444 {
3445   DBUG_ENTER("compChangeMask");
3446   bool found_varpart;
3447   change_mask= 0;
3448   Uint32 old_sz= old_impl.m_columns.size();
3449   Uint32 sz= impl.m_columns.size();
3450 
3451   /* These are the supported properties that may be altered. */
3452   DBUG_PRINT("info", ("old_impl.m_internalName='%s' impl.m_internalName='%s'",
3453                       old_impl.m_internalName.c_str(),
3454                       impl.m_internalName.c_str()));
3455   if(impl.m_internalName != old_impl.m_internalName)
3456   {
3457     bool old_blob = is_ndb_blob_table(old_impl.m_externalName.c_str());
3458     bool new_blob = is_ndb_blob_table(impl.m_externalName.c_str());
3459     if (unlikely(old_blob != new_blob))
3460     {
3461       /* Attempt to alter to/from Blob part table name */
3462       DBUG_PRINT("info", ("Attempt to alter to/from Blob part table name"));
3463       goto invalid_alter_table;
3464     }
3465     AlterTableReq::setNameFlag(change_mask, true);
3466   }
3467   if(!impl.m_frm.equal(old_impl.m_frm))
3468     AlterTableReq::setFrmFlag(change_mask, true);
3469   if(!impl.m_fd.equal(old_impl.m_fd))
3470     AlterTableReq::setFragDataFlag(change_mask, true);
3471   if(!impl.m_range.equal(old_impl.m_range))
3472     AlterTableReq::setRangeListFlag(change_mask, true);
3473 
3474   /* No other property can be changed in alter table. */
3475   if(impl.m_logging != old_impl.m_logging ||
3476      impl.m_temporary != old_impl.m_temporary ||
3477      impl.m_row_gci != old_impl.m_row_gci ||
3478      impl.m_row_checksum != old_impl.m_row_checksum ||
3479      impl.m_kvalue != old_impl.m_kvalue ||
3480      impl.m_minLoadFactor != old_impl.m_minLoadFactor ||
3481      impl.m_maxLoadFactor != old_impl.m_maxLoadFactor ||
3482      impl.m_primaryTableId != old_impl.m_primaryTableId ||
3483      impl.m_max_rows != old_impl.m_max_rows ||
3484      impl.m_min_rows != old_impl.m_min_rows ||
3485      impl.m_default_no_part_flag != old_impl.m_default_no_part_flag ||
3486      impl.m_linear_flag != old_impl.m_linear_flag ||
3487      impl.m_fragmentType != old_impl.m_fragmentType ||
3488      impl.m_tablespace_name != old_impl.m_tablespace_name ||
3489      impl.m_tablespace_id != old_impl.m_tablespace_id ||
3490      impl.m_tablespace_version != old_impl.m_tablespace_version ||
3491      impl.m_id != old_impl.m_id ||
3492      impl.m_version != old_impl.m_version ||
3493      sz < old_sz ||
3494      impl.m_extra_row_gci_bits != old_impl.m_extra_row_gci_bits ||
3495      impl.m_extra_row_author_bits != old_impl.m_extra_row_author_bits)
3496   {
3497     DBUG_PRINT("info", ("Old and new table not compatible"));
3498     goto invalid_alter_table;
3499   }
3500 
3501   if (impl.m_fragmentCount != old_impl.m_fragmentCount)
3502   {
3503     if (impl.m_fragmentType != NdbDictionary::Object::HashMapPartition)
3504       goto invalid_alter_table;
3505     AlterTableReq::setAddFragFlag(change_mask, true);
3506   }
3507   else
3508   { // Changing hash map only supported if adding fragments
3509     if (impl.m_fragmentType == NdbDictionary::Object::HashMapPartition &&
3510         (impl.m_hash_map_id != old_impl.m_hash_map_id ||
3511          impl.m_hash_map_version != old_impl.m_hash_map_version))
3512     {
3513       goto invalid_alter_table;
3514     }
3515   }
3516 
3517 
3518   /*
3519     Check for new columns.
3520     We can add one or more new columns at the end, with some restrictions:
3521      - All existing columns must be unchanged.
3522      - The new column must be dynamic.
3523      - The new column must be nullable.
3524      - The new column must be memory based.
3525      - The new column can not be a primary key or distribution key.
3526      - There must already be at least one existing memory-stored dynamic or
3527        variable-sized column (so that the varpart is already allocated) or
3528        varPart must be forced
3529   */
3530   found_varpart= old_impl.getForceVarPart();
3531   for(Uint32 i= 0; i<old_sz; i++)
3532   {
3533     const NdbColumnImpl *col= impl.m_columns[i];
3534     if(!col->equal(*(old_impl.m_columns[i])))
3535     {
3536       DBUG_PRINT("info", ("Old and new column not equal"));
3537       goto invalid_alter_table;
3538     }
3539     if(col->m_storageType == NDB_STORAGETYPE_MEMORY &&
3540        (col->m_dynamic || col->m_arrayType != NDB_ARRAYTYPE_FIXED))
3541       found_varpart= true;
3542   }
3543 
3544   if(sz > old_sz)
3545   {
3546     if(!found_varpart)
3547     {
3548       DBUG_PRINT("info", ("No old dynamic column found"));
3549       goto invalid_alter_table;
3550     }
3551 
3552     for(Uint32 i=old_sz; i<sz; i++)
3553     {
3554       const NdbColumnImpl *col= impl.m_columns[i];
3555       if(!col->m_dynamic || !col->m_nullable ||
3556          !col->m_defaultValue.empty() ||
3557          col->m_storageType == NDB_STORAGETYPE_DISK ||
3558          col->m_pk ||
3559          col->m_distributionKey ||
3560          col->m_autoIncrement ||                   // ToDo: allow this?
3561 	 (col->getBlobType() && col->getPartSize())
3562          )
3563       {
3564         goto invalid_alter_table;
3565       }
3566     }
3567     AlterTableReq::setAddAttrFlag(change_mask, true);
3568   }
3569 
3570   DBUG_RETURN(0);
3571 
3572  invalid_alter_table:
3573   m_error.code = 741;                           // "Unsupported alter table"
3574   DBUG_RETURN(-1);
3575 }
3576 
3577 int
serializeTableDesc(Ndb & ndb,NdbTableImpl & impl,UtilBufferWriter & w)3578 NdbDictInterface::serializeTableDesc(Ndb & ndb,
3579 				     NdbTableImpl & impl,
3580 				     UtilBufferWriter & w)
3581 {
3582   unsigned i, err;
3583   DBUG_ENTER("NdbDictInterface::serializeTableDesc");
3584 
3585   impl.computeAggregates();
3586 
3587   if((unsigned)impl.getNoOfPrimaryKeys() > NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY){
3588     m_error.code= 4317;
3589     DBUG_RETURN(-1);
3590   }
3591   unsigned sz = impl.m_columns.size();
3592   if (sz > NDB_MAX_ATTRIBUTES_IN_TABLE){
3593     m_error.code= 4318;
3594     DBUG_RETURN(-1);
3595   }
3596 
3597   /*
3598      TODO RONM: Here I need to insert checks for fragment array and
3599      range or list array
3600   */
3601 
3602   //validate();
3603   //aggregate();
3604 
3605   DictTabInfo::Table *tmpTab;
3606 
3607   tmpTab = (DictTabInfo::Table*)NdbMem_Allocate(sizeof(DictTabInfo::Table));
3608   if (!tmpTab)
3609   {
3610     m_error.code = 4000;
3611     DBUG_RETURN(-1);
3612   }
3613   tmpTab->init();
3614   BaseString::snprintf(tmpTab->TableName, sizeof(tmpTab->TableName),
3615                        "%s", impl.m_internalName.c_str());
3616 
3617   Uint32 distKeys= 0;
3618   for(i = 0; i<sz; i++) {
3619     const NdbColumnImpl * col = impl.m_columns[i];
3620     if (col == NULL) {
3621       m_error.code = 4272;
3622       NdbMem_Free((void*)tmpTab);
3623       DBUG_RETURN(-1);
3624     }
3625     if (col->m_distributionKey)
3626     {
3627       distKeys++;
3628       if (!col->m_pk)
3629       {
3630         m_error.code = 4327;
3631         NdbMem_Free((void*)tmpTab);
3632         DBUG_RETURN(-1);
3633       }
3634     }
3635   }
3636   if (distKeys == impl.m_noOfKeys)
3637     distKeys= 0;
3638   impl.m_noOfDistributionKeys= distKeys;
3639 
3640 
3641   // Check max length of frm data
3642   if (impl.m_frm.length() > MAX_FRM_DATA_SIZE){
3643     m_error.code= 1229;
3644     NdbMem_Free((void*)tmpTab);
3645     DBUG_RETURN(-1);
3646   }
3647   /*
3648     TODO RONM: This needs to change to dynamic arrays instead
3649     Frm Data, FragmentData, TablespaceData, RangeListData, TsNameData
3650   */
3651   tmpTab->FrmLen = impl.m_frm.length();
3652   memcpy(tmpTab->FrmData, impl.m_frm.get_data(), impl.m_frm.length());
3653 
3654   {
3655     /**
3656      * NOTE: fragment data is currently an array of Uint16
3657      *       and len is specified in bytes (yuck)
3658      *       please change to Uint32 and len == count
3659      */
3660     const Uint32* src = impl.m_fd.getBase();
3661     tmpTab->FragmentDataLen = 2*impl.m_fd.size();
3662     for (Uint32 i = 0; i<impl.m_fd.size(); i++)
3663       tmpTab->FragmentData[i] = (Uint16)src[i];
3664   }
3665 
3666   {
3667     /**
3668      * NOTE: len is specified in bytes (yuck)
3669      *       please change to len == count
3670      */
3671     tmpTab->RangeListDataLen = 4*impl.m_range.size();
3672     memcpy(tmpTab->RangeListData, impl.m_range.getBase(),4*impl.m_range.size());
3673   }
3674 
3675   tmpTab->FragmentCount= impl.m_fragmentCount;
3676   tmpTab->TableLoggedFlag = impl.m_logging;
3677   tmpTab->TableTemporaryFlag = impl.m_temporary;
3678   tmpTab->RowGCIFlag = impl.m_row_gci;
3679   tmpTab->RowChecksumFlag = impl.m_row_checksum;
3680   tmpTab->TableKValue = impl.m_kvalue;
3681   tmpTab->MinLoadFactor = impl.m_minLoadFactor;
3682   tmpTab->MaxLoadFactor = impl.m_maxLoadFactor;
3683   tmpTab->TableType = DictTabInfo::UserTable;
3684   tmpTab->PrimaryTableId = impl.m_primaryTableId;
3685   tmpTab->NoOfAttributes = sz;
3686   tmpTab->MaxRowsHigh = (Uint32)(impl.m_max_rows >> 32);
3687   tmpTab->MaxRowsLow = (Uint32)(impl.m_max_rows & 0xFFFFFFFF);
3688   tmpTab->MinRowsHigh = (Uint32)(impl.m_min_rows >> 32);
3689   tmpTab->MinRowsLow = (Uint32)(impl.m_min_rows & 0xFFFFFFFF);
3690   tmpTab->DefaultNoPartFlag = impl.m_default_no_part_flag;
3691   tmpTab->LinearHashFlag = impl.m_linear_flag;
3692   tmpTab->SingleUserMode = impl.m_single_user_mode;
3693   tmpTab->ForceVarPartFlag = impl.m_force_var_part;
3694   tmpTab->ExtraRowGCIBits = impl.m_extra_row_gci_bits;
3695   tmpTab->ExtraRowAuthorBits = impl.m_extra_row_author_bits;
3696 
3697   tmpTab->FragmentType = getKernelConstant(impl.m_fragmentType,
3698  					   fragmentTypeMapping,
3699 					   DictTabInfo::AllNodesSmallTable);
3700   tmpTab->TableVersion = rand();
3701 
3702   tmpTab->HashMapObjectId = impl.m_hash_map_id;
3703   tmpTab->HashMapVersion = impl.m_hash_map_version;
3704   tmpTab->TableStorageType = impl.m_storageType;
3705 
3706   const char *tablespace_name= impl.m_tablespace_name.c_str();
3707 loop:
3708   if(impl.m_tablespace_version != ~(Uint32)0)
3709   {
3710     tmpTab->TablespaceId = impl.m_tablespace_id;
3711     tmpTab->TablespaceVersion = impl.m_tablespace_version;
3712   }
3713   else if(strlen(tablespace_name))
3714   {
3715     NdbTablespaceImpl tmp;
3716     if(get_filegroup(tmp, NdbDictionary::Object::Tablespace,
3717 		     tablespace_name) == 0)
3718     {
3719       tmpTab->TablespaceId = tmp.m_id;
3720       tmpTab->TablespaceVersion = tmp.m_version;
3721     }
3722     else
3723     {
3724       // error set by get filegroup
3725       if (m_error.code == 723)
3726 	m_error.code = 755;
3727 
3728       NdbMem_Free((void*)tmpTab);
3729       DBUG_RETURN(-1);
3730     }
3731   }
3732   else
3733   {
3734     for(i = 0; i<sz; i++)
3735     {
3736       if(impl.m_columns[i]->m_storageType == NDB_STORAGETYPE_DISK)
3737       {
3738 	tablespace_name = "DEFAULT-TS";
3739 	goto loop;
3740       }
3741     }
3742   }
3743 
3744   SimpleProperties::UnpackStatus s;
3745   w.reset();
3746   s = SimpleProperties::pack(w,
3747 			     tmpTab,
3748 			     DictTabInfo::TableMapping,
3749 			     DictTabInfo::TableMappingSize, true);
3750 
3751   if(s != SimpleProperties::Eof){
3752     abort();
3753   }
3754   NdbMem_Free((void*)tmpTab);
3755 
3756   DBUG_PRINT("info",("impl.m_noOfDistributionKeys: %d impl.m_noOfKeys: %d distKeys: %d",
3757 		     impl.m_noOfDistributionKeys, impl.m_noOfKeys, distKeys));
3758   if (distKeys == impl.m_noOfKeys)
3759     distKeys= 0;
3760   impl.m_noOfDistributionKeys= distKeys;
3761 
3762   for(i = 0; i<sz; i++){
3763     const NdbColumnImpl * col = impl.m_columns[i];
3764     if(col == 0)
3765       continue;
3766 
3767     DBUG_PRINT("info",("column: %s(%d) col->m_distributionKey: %d"
3768                        " array type: %u storage type: %u",
3769 		       col->m_name.c_str(), i, col->m_distributionKey,
3770                        col->m_arrayType, col->m_storageType));
3771     DictTabInfo::Attribute tmpAttr; tmpAttr.init();
3772     BaseString::snprintf(tmpAttr.AttributeName, sizeof(tmpAttr.AttributeName),
3773 	     "%s", col->m_name.c_str());
3774     tmpAttr.AttributeId = col->m_attrId;
3775     tmpAttr.AttributeKeyFlag = col->m_pk;
3776     tmpAttr.AttributeNullableFlag = col->m_nullable;
3777     tmpAttr.AttributeDKey = distKeys ? col->m_distributionKey : 0;
3778 
3779     tmpAttr.AttributeExtType = (Uint32)col->m_type;
3780     tmpAttr.AttributeExtPrecision = ((unsigned)col->m_precision & 0xFFFF);
3781     tmpAttr.AttributeExtScale = col->m_scale;
3782     tmpAttr.AttributeExtLength = col->m_length;
3783     tmpAttr.AttributeArrayType = col->m_arrayType;
3784 
3785     if(col->m_pk)
3786       tmpAttr.AttributeStorageType = NDB_STORAGETYPE_MEMORY;
3787     else
3788       tmpAttr.AttributeStorageType = col->m_storageType;
3789     tmpAttr.AttributeDynamic = (col->m_dynamic ? 1 : 0);
3790 
3791     if (col->getBlobType()) {
3792       tmpAttr.AttributeArrayType = col->m_arrayType;
3793       tmpAttr.AttributeStorageType = NDB_STORAGETYPE_MEMORY;
3794     }
3795 
3796     // check type and compute attribute size and array size
3797     if (! tmpAttr.translateExtType()) {
3798       m_error.code= 703;
3799       DBUG_RETURN(-1);
3800     }
3801     // charset is defined exactly for char types
3802     if (col->getCharType() != (col->m_cs != NULL)) {
3803       m_error.code= 703;
3804       DBUG_RETURN(-1);
3805     }
3806     // primary key type check
3807     if (col->m_pk &&
3808         (err = NdbSqlUtil::check_column_for_pk(col->m_type, col->m_cs)))
3809     {
3810       m_error.code= err;
3811       DBUG_RETURN(-1);
3812     }
3813     // all PK types now allowed as dist key
3814     // charset in upper half of precision
3815     if (col->getCharType()) {
3816       tmpAttr.AttributeExtPrecision |= (col->m_cs->number << 16);
3817     }
3818 
3819     tmpAttr.AttributeAutoIncrement = col->m_autoIncrement;
3820     {
3821       Uint32 ah;
3822       Uint32 byteSize = col->m_defaultValue.length();
3823       assert(byteSize <= NDB_MAX_TUPLE_SIZE);
3824 
3825       if (byteSize)
3826       {
3827         if (unlikely(! ndb_native_default_support(ndb.getMinDbNodeVersion())))
3828         {
3829           /* We can't create a table with native defaults with
3830            * this kernel version
3831            * Schema feature requires data node upgrade
3832            */
3833           m_error.code = 794;
3834           DBUG_RETURN(-1);
3835         }
3836       }
3837 
3838       //The AttributeId of a column isn't decided now, so 0 is used.
3839       AttributeHeader::init(&ah, 0, byteSize);
3840 
3841       /* Table meta-info is normally stored in network byte order
3842        * by SimpleProperties
3843        * For the default value 'Blob' we do the work
3844        */
3845       Uint32 a = htonl(ah);
3846       memcpy(tmpAttr.AttributeDefaultValue, &a, sizeof(Uint32));
3847       memcpy(tmpAttr.AttributeDefaultValue + sizeof(Uint32),
3848              col->m_defaultValue.get_data(), byteSize);
3849       Uint32 defValByteLen = ((col->m_defaultValue.length() + 3) / 4) * 4;
3850       tmpAttr.AttributeDefaultValueLen = defValByteLen + sizeof(Uint32);
3851 
3852       if (defValByteLen)
3853       {
3854         /* In-place host->network conversion */
3855         NdbSqlUtil::convertByteOrder(tmpAttr.AttributeExtType,
3856                                      tmpAttr.AttributeSize,
3857                                      tmpAttr.AttributeArrayType,
3858                                      tmpAttr.AttributeArraySize,
3859                                      tmpAttr.AttributeDefaultValue +
3860                                      sizeof(Uint32),
3861                                      defValByteLen);
3862       }
3863     }
3864     s = SimpleProperties::pack(w,
3865 			       &tmpAttr,
3866 			       DictTabInfo::AttributeMapping,
3867 			       DictTabInfo::AttributeMappingSize, true);
3868     w.add(DictTabInfo::AttributeEnd, 1);
3869   }
3870 
3871   DBUG_RETURN(0);
3872 }
3873 
3874 int
sendAlterTable(const NdbTableImpl & impl,Uint32 change_mask,UtilBufferWriter & w)3875 NdbDictInterface::sendAlterTable(const NdbTableImpl &impl,
3876                                  Uint32 change_mask,
3877                                  UtilBufferWriter &w)
3878 {
3879   LinearSectionPtr ptr[1];
3880   ptr[0].p = (Uint32*)m_buffer.get_data();
3881   ptr[0].sz = m_buffer.length() / 4;
3882   NdbApiSignal tSignal(m_reference);
3883   tSignal.theReceiversBlockNumber = DBDICT;
3884   tSignal.theVerId_signalNumber   = GSN_ALTER_TABLE_REQ;
3885   tSignal.theLength = AlterTableReq::SignalLength;
3886 
3887   AlterTableReq * req = CAST_PTR(AlterTableReq, tSignal.getDataPtrSend());
3888 
3889   req->clientRef = m_reference;
3890   req->clientData = 0;
3891   req->transId = m_tx.transId();
3892   req->transKey = m_tx.transKey();
3893   req->requestInfo = 0;
3894   req->requestInfo |= m_tx.requestFlags();
3895   req->tableId = impl.m_id;
3896   req->tableVersion = impl.m_version;
3897   req->changeMask = change_mask;
3898 
3899   int errCodes[] = { AlterTableRef::NotMaster, AlterTableRef::Busy, 0 };
3900   int ret= dictSignal(&tSignal, ptr, 1,
3901                       0,                        // master
3902                       WAIT_ALTER_TAB_REQ,
3903                       DICT_WAITFOR_TIMEOUT, 100,
3904                       errCodes);
3905 
3906   if(m_error.code == AlterTableRef::InvalidTableVersion) {
3907     // Clear caches and try again
3908     return(INCOMPATIBLE_VERSION);
3909   }
3910 
3911   return ret;
3912 }
3913 
3914 int
sendCreateTable(const NdbTableImpl & impl,UtilBufferWriter & w)3915 NdbDictInterface::sendCreateTable(const NdbTableImpl &impl,
3916                                   UtilBufferWriter &w)
3917 {
3918   LinearSectionPtr ptr[1];
3919   ptr[0].p = (Uint32*)m_buffer.get_data();
3920   ptr[0].sz = m_buffer.length() / 4;
3921   NdbApiSignal tSignal(m_reference);
3922   tSignal.theReceiversBlockNumber = DBDICT;
3923   tSignal.theVerId_signalNumber   = GSN_CREATE_TABLE_REQ;
3924   tSignal.theLength = CreateTableReq::SignalLength;
3925 
3926   CreateTableReq * req = CAST_PTR(CreateTableReq, tSignal.getDataPtrSend());
3927   req->clientRef = m_reference;
3928   req->clientData = 0;
3929   req->requestInfo = 0;
3930   req->requestInfo |= m_tx.requestFlags();
3931   req->transId = m_tx.transId();
3932   req->transKey = m_tx.transKey();
3933 
3934   int errCodes[]= { CreateTableRef::Busy, CreateTableRef::NotMaster, 0 };
3935   int ret= dictSignal(&tSignal, ptr, 1,
3936                       0,                        // master node
3937                       WAIT_CREATE_INDX_REQ,
3938                       DICT_WAITFOR_TIMEOUT, 100,
3939                       errCodes);
3940 
3941   return ret;
3942 }
3943 
3944 void
execCREATE_TABLE_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])3945 NdbDictInterface::execCREATE_TABLE_CONF(const NdbApiSignal * signal,
3946 					const LinearSectionPtr ptr[3])
3947 {
3948   DBUG_ENTER("NdbDictInterface::execCREATE_TABLE_CONF");
3949   const CreateTableConf* const conf=
3950     CAST_CONSTPTR(CreateTableConf, signal->getDataPtr());
3951   m_buffer.grow(4 * 2); // 2 words
3952   Uint32* data = (Uint32*)m_buffer.get_data();
3953   data[0] = conf->tableId;
3954   data[1] = conf->tableVersion;
3955   m_impl->theWaiter.signal(NO_WAIT);
3956   DBUG_VOID_RETURN;
3957 }
3958 
3959 void
execCREATE_TABLE_REF(const NdbApiSignal * sig,const LinearSectionPtr ptr[3])3960 NdbDictInterface::execCREATE_TABLE_REF(const NdbApiSignal * sig,
3961 				       const LinearSectionPtr ptr[3])
3962 {
3963   DBUG_ENTER("NdbDictInterface::execCREATE_TABLE_REF");
3964   const CreateTableRef* ref = CAST_CONSTPTR(CreateTableRef, sig->getDataPtr());
3965   m_error.code= ref->errorCode;
3966   DBUG_PRINT("info", ("Error code = %d", m_error.code));
3967   m_masterNodeId = ref->masterNodeId;
3968   m_impl->theWaiter.signal(NO_WAIT);
3969   DBUG_VOID_RETURN;
3970 }
3971 
3972 void
execALTER_TABLE_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])3973 NdbDictInterface::execALTER_TABLE_CONF(const NdbApiSignal * signal,
3974                                        const LinearSectionPtr ptr[3])
3975 {
3976   DBUG_ENTER("NdbDictInterface::execALTER_TABLE_CONF");
3977   m_impl->theWaiter.signal(NO_WAIT);
3978   DBUG_VOID_RETURN;
3979 }
3980 
3981 void
execALTER_TABLE_REF(const NdbApiSignal * sig,const LinearSectionPtr ptr[3])3982 NdbDictInterface::execALTER_TABLE_REF(const NdbApiSignal * sig,
3983 				      const LinearSectionPtr ptr[3])
3984 {
3985   DBUG_ENTER("NdbDictInterface::execALTER_TABLE_REF");
3986   const AlterTableRef * ref = CAST_CONSTPTR(AlterTableRef, sig->getDataPtr());
3987   m_error.code= ref->errorCode;
3988   DBUG_PRINT("info", ("Error code = %d", m_error.code));
3989   m_masterNodeId = ref->masterNodeId;
3990   m_impl->theWaiter.signal(NO_WAIT);
3991   DBUG_VOID_RETURN;
3992 }
3993 
3994 /*****************************************************************
3995  * Drop table
3996  */
3997 int
dropTable(const char * name)3998 NdbDictionaryImpl::dropTable(const char * name)
3999 {
4000   DBUG_ENTER("NdbDictionaryImpl::dropTable");
4001   DBUG_PRINT("enter",("name: %s", name));
4002   ASSERT_NOT_MYSQLD;
4003   NdbTableImpl * tab = getTable(name);
4004   if(tab == 0){
4005     DBUG_RETURN(-1);
4006   }
4007   int ret = dropTable(* tab);
4008   // If table stored in cache is incompatible with the one in the kernel
4009   // we must clear the cache and try again
4010   if (ret == INCOMPATIBLE_VERSION) {
4011     const BaseString internalTableName(m_ndb.internalize_table_name(name));
4012     DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName.c_str()));
4013     m_localHash.drop(internalTableName.c_str());
4014     m_globalHash->lock();
4015     m_globalHash->release(tab, 1);
4016     m_globalHash->unlock();
4017     DBUG_RETURN(dropTable(name));
4018   }
4019 
4020   DBUG_RETURN(ret);
4021 }
4022 
4023 static bool
dropTableAllowDropChildFK(const NdbTableImpl & impl,const NdbDictionary::ForeignKey & fk,int flags)4024 dropTableAllowDropChildFK(const NdbTableImpl& impl,
4025                           const NdbDictionary::ForeignKey& fk,
4026                           int flags)
4027 {
4028   DBUG_ENTER("dropTableAllowDropChildFK");
4029   const char* table = impl.m_internalName.c_str();
4030   const char* child = fk.getChildTable();
4031   const char* parent = fk.getParentTable();
4032   DBUG_PRINT("info", ("table: %s child: %s parent: %s",
4033                       table, child, parent));
4034   const bool is_child = strcmp(table, child) == 0;
4035   const bool is_parent = strcmp(table, parent) == 0;
4036   if (flags & NdbDictionary::Dictionary::DropTableCascadeConstraints)
4037   {
4038     DBUG_PRINT("info", ("return true - cascade_constraints is on"));
4039     DBUG_RETURN(true);
4040   }
4041   if (is_child && !is_parent)
4042   {
4043     DBUG_PRINT("info", ("return true - !is_parent && is_child"));
4044     DBUG_RETURN(true);
4045   }
4046   if (is_child && is_parent)
4047   {
4048     // same table (self ref FK)
4049     DBUG_PRINT("info", ("return true - is_child && is_parent"));
4050     DBUG_RETURN(true);
4051   }
4052   if (flags & NdbDictionary::Dictionary::DropTableCascadeConstraintsDropDB)
4053   {
4054     // first part is db...
4055     const char * end = strchr(parent, table_name_separator);
4056     if (end != NULL)
4057     {
4058       size_t len = end - parent;
4059       if (strncmp(parent, child, len) == 0)
4060       {
4061         DBUG_PRINT("info",
4062                    ("return OK - DropTableCascadeConstraintsDropDB & same DB"));
4063         DBUG_RETURN(true);
4064       }
4065     }
4066   }
4067 
4068   DBUG_PRINT("info", ("return false"));
4069   DBUG_RETURN(false);
4070 }
4071 
4072 int
dropTable(NdbTableImpl & impl)4073 NdbDictionaryImpl::dropTable(NdbTableImpl & impl)
4074 {
4075   int res;
4076   const char * name = impl.getName();
4077   if(impl.m_status == NdbDictionary::Object::New){
4078     return dropTable(name);
4079   }
4080 
4081   if (impl.m_indexType != NdbDictionary::Object::TypeUndefined)
4082   {
4083     m_receiver.m_error.code= 1228;
4084     return -1;
4085   }
4086 
4087   List list;
4088   if ((res = listDependentObjects(list, impl.m_id)) == -1){
4089     return -1;
4090   }
4091 
4092   // drop FKs before indexes (even if DBDICT may not care)
4093 
4094   for (unsigned i = 0; i < list.count; i++) {
4095     const List::Element& element = list.elements[i];
4096     if (DictTabInfo::isForeignKey(element.type))
4097     {
4098       NdbDictionary::ForeignKey fk;
4099       if ((res = getForeignKey(fk, element.name)) != 0)
4100       {
4101         return -1;
4102       }
4103       const bool cascade_constraints = true;
4104       if (!dropTableAllowDropChildFK(impl, fk, cascade_constraints))
4105       {
4106         m_receiver.m_error.code = 21080;
4107         return -1;
4108       }
4109       if ((res = dropForeignKey(fk)) != 0)
4110       {
4111         return -1;
4112       }
4113     }
4114   }
4115 
4116   for (unsigned i = 0; i < list.count; i++) {
4117     const List::Element& element = list.elements[i];
4118     if (DictTabInfo::isIndex(element.type))
4119     {
4120       // note can also return -2 in error case(INCOMPATIBLE_VERSION),
4121       // hence compare with != 0
4122       if ((res = dropIndex(element.name, name, true)) != 0)
4123       {
4124         return -1;
4125       }
4126     }
4127   }
4128 
4129   if (impl.m_noOfBlobs != 0) {
4130     if (dropBlobTables(impl) != 0){
4131       return -1;
4132     }
4133   }
4134 
4135   int ret = m_receiver.dropTable(impl);
4136   if(ret == 0 || m_error.code == 709 || m_error.code == 723){
4137     const char * internalTableName = impl.m_internalName.c_str();
4138 
4139 
4140     m_localHash.drop(internalTableName);
4141     m_globalHash->lock();
4142     m_globalHash->release(&impl, 1);
4143     m_globalHash->unlock();
4144 
4145     return 0;
4146   }
4147 
4148   return ret;
4149 }
4150 
4151 int
dropTableGlobal(NdbTableImpl & impl)4152 NdbDictionaryImpl::dropTableGlobal(NdbTableImpl & impl)
4153 {
4154   return dropTableGlobal(impl, 0);
4155 }
4156 
4157 int
dropTableGlobal(NdbTableImpl & impl,int flags)4158 NdbDictionaryImpl::dropTableGlobal(NdbTableImpl & impl, int flags)
4159 {
4160   int res;
4161   DBUG_ENTER("NdbDictionaryImpl::dropTableGlobal");
4162   assert(impl.m_status != NdbDictionary::Object::New);
4163   assert(impl.m_indexType == NdbDictionary::Object::TypeUndefined);
4164 
4165   List list;
4166   if ((res = listDependentObjects(list, impl.m_id)) == -1){
4167     ERR_RETURN(getNdbError(), -1);
4168   }
4169 
4170   {
4171     /**
4172      * To keep this method atomic...
4173      *   we first iterate the list and perform checks...
4174      *   before doing any drops
4175      *
4176      * Otherwise, some drops might have been performed and then we return error
4177      *   the semantics is a bit unclear for this situation but new code
4178      *   trying to handle foreign_key_checks relies to this
4179      *   being possible
4180      */
4181     for (unsigned i = 0; i < list.count; i++)
4182     {
4183       const List::Element& element = list.elements[i];
4184 
4185       if (DictTabInfo::isForeignKey(element.type))
4186       {
4187         NdbDictionary::ForeignKey fk;
4188         if ((res = getForeignKey(fk, element.name)) != 0)
4189         {
4190           ERR_RETURN(getNdbError(), -1);
4191         }
4192         if (!dropTableAllowDropChildFK(impl, fk, flags))
4193         {
4194           m_receiver.m_error.code = 21080;
4195           ERR_RETURN(getNdbError(), -1);
4196         }
4197       }
4198     }
4199   }
4200 
4201   /**
4202    * Need to drop all FK first...as they might depend on indexes
4203    * No need to call dropTableAllowDropChildFK again...
4204    */
4205   for (unsigned i = 0; i < list.count; i++)
4206   {
4207     const List::Element& element = list.elements[i];
4208 
4209     if (DictTabInfo::isForeignKey(element.type))
4210     {
4211       NdbDictionary::ForeignKey fk;
4212       if ((res = getForeignKey(fk, element.name)) != 0)
4213       {
4214         ERR_RETURN(getNdbError(), -1);
4215       }
4216 
4217       if ((res = dropForeignKey(fk)) != 0)
4218       {
4219         ERR_RETURN(getNdbError(), -1);
4220       }
4221     }
4222   }
4223 
4224   /**
4225    * And then drop the indexes
4226    */
4227   for (unsigned i = 0; i < list.count; i++)
4228   {
4229     const List::Element& element = list.elements[i];
4230     if (DictTabInfo::isIndex(element.type))
4231     {
4232       // note can also return -2 in error case(INCOMPATIBLE_VERSION),
4233       // hence compare with != 0
4234       NdbIndexImpl *idx= getIndexGlobal(element.name, impl);
4235       if (idx == NULL)
4236       {
4237         ERR_RETURN(getNdbError(), -1);
4238       }
4239 
4240       // note can also return -2 in error case(INCOMPATIBLE_VERSION),
4241       // hence compare with != 0
4242       if ((res = dropIndexGlobal(*idx, true)) != 0)
4243       {
4244         releaseIndexGlobal(*idx, 1);
4245         ERR_RETURN(getNdbError(), -1);
4246       }
4247       releaseIndexGlobal(*idx, 1);
4248     }
4249   }
4250 
4251   if (impl.m_noOfBlobs != 0) {
4252     if (dropBlobTables(impl) != 0){
4253       ERR_RETURN(getNdbError(), -1);
4254     }
4255   }
4256 
4257   int ret = m_receiver.dropTable(impl);
4258   impl.m_status = NdbDictionary::Object::Invalid;
4259   if(ret == 0 || m_error.code == 709 || m_error.code == 723)
4260   {
4261     DBUG_RETURN(0);
4262   }
4263 
4264   ERR_RETURN(getNdbError(), ret);
4265 }
4266 
4267 int
dropBlobTables(NdbTableImpl & t)4268 NdbDictionaryImpl::dropBlobTables(NdbTableImpl & t)
4269 {
4270   DBUG_ENTER("NdbDictionaryImpl::dropBlobTables");
4271   for (unsigned i = 0; i < t.m_columns.size(); i++) {
4272     NdbColumnImpl & c = *t.m_columns[i];
4273     if (! c.getBlobType() || c.getPartSize() == 0)
4274       continue;
4275     NdbTableImpl* bt = c.m_blobTable;
4276     if (bt == NULL) {
4277       DBUG_PRINT("info", ("col %s: blob table pointer is NULL",
4278                           c.m_name.c_str()));
4279       continue; // "force" mode on
4280     }
4281     // drop directly - by-pass cache
4282     int ret = m_receiver.dropTable(*c.m_blobTable);
4283     if (ret != 0) {
4284       DBUG_PRINT("info", ("col %s: blob table %s: error %d",
4285                  c.m_name.c_str(), bt->m_internalName.c_str(), m_error.code));
4286       if (! (ret == 709 || ret == 723)) // "force" mode on
4287         ERR_RETURN(getNdbError(), -1);
4288     }
4289     // leave c.m_blobTable defined
4290   }
4291   DBUG_RETURN(0);
4292 }
4293 
4294 int
dropTable(const NdbTableImpl & impl)4295 NdbDictInterface::dropTable(const NdbTableImpl & impl)
4296 {
4297   NdbApiSignal tSignal(m_reference);
4298   tSignal.theReceiversBlockNumber = DBDICT;
4299   tSignal.theVerId_signalNumber   = GSN_DROP_TABLE_REQ;
4300   tSignal.theLength = DropTableReq::SignalLength;
4301 
4302   DropTableReq * req = CAST_PTR(DropTableReq, tSignal.getDataPtrSend());
4303   req->clientRef = m_reference;
4304   req->clientData = 0;
4305   req->transId = m_tx.transId();
4306   req->transKey = m_tx.transKey();
4307   req->requestInfo = 0;
4308   req->requestInfo |= m_tx.requestFlags();
4309   req->tableId = impl.m_id;
4310   req->tableVersion = impl.m_version;
4311 
4312   int errCodes[] =
4313     { DropTableRef::NoDropTableRecordAvailable,
4314       DropTableRef::NotMaster,
4315       DropTableRef::Busy, 0 };
4316   int r = dictSignal(&tSignal, 0, 0,
4317 		     0, // master
4318 		     WAIT_DROP_TAB_REQ,
4319 		     DICT_WAITFOR_TIMEOUT, 100,
4320 		     errCodes);
4321   if(m_error.code == DropTableRef::InvalidTableVersion) {
4322     // Clear caches and try again
4323     return INCOMPATIBLE_VERSION;
4324   }
4325   return r;
4326 }
4327 
4328 void
execDROP_TABLE_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4329 NdbDictInterface::execDROP_TABLE_CONF(const NdbApiSignal * signal,
4330 				      const LinearSectionPtr ptr[3])
4331 {
4332   DBUG_ENTER("NdbDictInterface::execDROP_TABLE_CONF");
4333   //DropTableConf* const conf = CAST_CONSTPTR(DropTableConf, signal->getDataPtr());
4334 
4335   m_impl->theWaiter.signal(NO_WAIT);
4336   DBUG_VOID_RETURN;
4337 }
4338 
4339 void
execDROP_TABLE_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4340 NdbDictInterface::execDROP_TABLE_REF(const NdbApiSignal * signal,
4341 				     const LinearSectionPtr ptr[3])
4342 {
4343   DBUG_ENTER("NdbDictInterface::execDROP_TABLE_REF");
4344   const DropTableRef* ref = CAST_CONSTPTR(DropTableRef, signal->getDataPtr());
4345   m_error.code= ref->errorCode;
4346   DBUG_PRINT("info", ("Error code = %d", m_error.code));
4347   m_masterNodeId = ref->masterNodeId;
4348   m_impl->theWaiter.signal(NO_WAIT);
4349   DBUG_VOID_RETURN;
4350 }
4351 
4352 int
invalidateObject(NdbTableImpl & impl)4353 NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl)
4354 {
4355   const char * internalTableName = impl.m_internalName.c_str();
4356   DBUG_ENTER("NdbDictionaryImpl::invalidateObject");
4357   DBUG_PRINT("enter", ("internal_name: %s", internalTableName));
4358 
4359   m_localHash.drop(internalTableName);
4360   m_globalHash->lock();
4361   m_globalHash->release(&impl, 1);
4362   m_globalHash->unlock();
4363   DBUG_RETURN(0);
4364 }
4365 
4366 int
removeCachedObject(NdbTableImpl & impl)4367 NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl)
4368 {
4369   const char * internalTableName = impl.m_internalName.c_str();
4370   DBUG_ENTER("NdbDictionaryImpl::removeCachedObject");
4371   DBUG_PRINT("enter", ("internal_name: %s", internalTableName));
4372 
4373   m_localHash.drop(internalTableName);
4374   m_globalHash->lock();
4375   m_globalHash->release(&impl);
4376   m_globalHash->unlock();
4377   DBUG_RETURN(0);
4378 }
4379 
4380 int
create_index_obj_from_table(NdbIndexImpl ** dst,NdbTableImpl * tab,const NdbTableImpl * prim)4381 NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
4382 					      NdbTableImpl* tab,
4383 					      const NdbTableImpl* prim)
4384 {
4385   DBUG_ENTER("NdbDictInterface::create_index_obj_from_table");
4386   NdbIndexImpl *idx = new NdbIndexImpl();
4387   if (idx == NULL)
4388   {
4389     errno = ENOMEM;
4390     DBUG_RETURN(-1);
4391   }
4392   idx->m_version = tab->m_version;
4393   idx->m_status = tab->m_status;
4394   idx->m_id = tab->m_id;
4395   if (!idx->m_externalName.assign(tab->getName()) ||
4396       !idx->m_tableName.assign(prim->m_externalName))
4397   {
4398     delete idx;
4399     errno = ENOMEM;
4400     DBUG_RETURN(-1);
4401   }
4402   NdbDictionary::Object::Type type = idx->m_type = tab->m_indexType;
4403   idx->m_logging = tab->m_logging;
4404   idx->m_temporary = tab->m_temporary;
4405 
4406   const Uint32 distKeys = prim->m_noOfDistributionKeys;
4407   Uint32 keyCount =
4408     (type == NdbDictionary::Object::UniqueHashIndex) ?
4409     tab->m_noOfKeys : (distKeys ? distKeys : prim->m_noOfKeys);
4410   const Uint32 fullKeyCount = keyCount;
4411 
4412   unsigned i;
4413   // skip last attribute (NDB$PK or NDB$TNODE)
4414   for(i = 0; i+1<tab->m_columns.size(); i++){
4415     NdbColumnImpl* org = tab->m_columns[i];
4416 
4417     NdbColumnImpl* col = new NdbColumnImpl;
4418     if (col == NULL)
4419     {
4420       errno = ENOMEM;
4421       delete idx;
4422       DBUG_RETURN(-1);
4423     }
4424     // Copy column definition
4425     *col = * org;
4426     if (idx->m_columns.push_back(col))
4427     {
4428       delete col;
4429       delete idx;
4430       DBUG_RETURN(-1);
4431     }
4432 
4433     /**
4434      * reverse map
4435      */
4436     const NdbColumnImpl* primCol = prim->getColumn(col->getName());
4437     if (primCol == 0)
4438     {
4439       delete idx;
4440       DBUG_RETURN(-1);
4441     }
4442 
4443     int key_id = primCol->getColumnNo();
4444     int fill = -1;
4445     idx->m_key_ids.fill(key_id, fill);
4446     idx->m_key_ids[key_id] = i;
4447     col->m_keyInfoPos = key_id;
4448 
4449     if(type == NdbDictionary::Object::OrderedIndex &&
4450        (primCol->m_distributionKey ||
4451 	(distKeys == 0 && primCol->getPrimaryKey())))
4452     {
4453       keyCount--;
4454       org->m_distributionKey = 1;
4455     }
4456     else if (type == NdbDictionary::Object::UniqueHashIndex)
4457     {
4458       keyCount--;
4459       org->m_distributionKey = 1;
4460     }
4461   }
4462 
4463   if(keyCount == 0)
4464   {
4465     tab->m_noOfDistributionKeys = fullKeyCount;
4466   }
4467   else
4468   {
4469     for(i = 0; i+1<tab->m_columns.size(); i++)
4470       tab->m_columns[i]->m_distributionKey = 0;
4471   }
4472 
4473   idx->m_table_id = prim->getObjectId();
4474   idx->m_table_version = prim->getObjectVersion();
4475 
4476   * dst = idx;
4477   DBUG_PRINT("exit", ("m_id: %d  m_version: %d", idx->m_id, idx->m_version));
4478   DBUG_RETURN(0);
4479 }
4480 
4481 /*****************************************************************
4482  * Create index
4483  */
4484 int
createIndex(NdbIndexImpl & ix,bool offline)4485 NdbDictionaryImpl::createIndex(NdbIndexImpl &ix, bool offline)
4486 {
4487   ASSERT_NOT_MYSQLD;
4488   NdbTableImpl* tab = getTable(ix.getTable());
4489   if(tab == 0){
4490     m_error.code = 4249;
4491     return -1;
4492   }
4493 
4494   return m_receiver.createIndex(m_ndb, ix, * tab, offline);
4495 }
4496 
4497 int
createIndex(NdbIndexImpl & ix,NdbTableImpl & tab,bool offline)4498 NdbDictionaryImpl::createIndex(NdbIndexImpl &ix, NdbTableImpl &tab,
4499                                bool offline)
4500 {
4501   return m_receiver.createIndex(m_ndb, ix, tab, offline);
4502 }
4503 
4504 int
createIndex(Ndb & ndb,const NdbIndexImpl & impl,const NdbTableImpl & table,bool offline)4505 NdbDictInterface::createIndex(Ndb & ndb,
4506 			      const NdbIndexImpl & impl,
4507 			      const NdbTableImpl & table,
4508                               bool offline)
4509 {
4510   //validate();
4511   //aggregate();
4512   unsigned i, err;
4513   UtilBufferWriter w(m_buffer);
4514   const size_t len = strlen(impl.m_externalName.c_str()) + 1;
4515   if(len > MAX_TAB_NAME_SIZE) {
4516     m_error.code = 4241;
4517     return -1;
4518   }
4519   const BaseString internalName(
4520     ndb.internalize_index_name(&table, impl.getName()));
4521   w.add(DictTabInfo::TableName, internalName.c_str());
4522   w.add(DictTabInfo::TableLoggedFlag, impl.m_logging);
4523   w.add(DictTabInfo::TableTemporaryFlag, impl.m_temporary);
4524 
4525   NdbApiSignal tSignal(m_reference);
4526   tSignal.theReceiversBlockNumber = DBDICT;
4527   tSignal.theVerId_signalNumber   = GSN_CREATE_INDX_REQ;
4528   tSignal.theLength = CreateIndxReq::SignalLength;
4529 
4530   CreateIndxReq * const req = CAST_PTR(CreateIndxReq, tSignal.getDataPtrSend());
4531   req->clientRef = m_reference;
4532   req->clientData = 0;
4533   req->transId = m_tx.transId();
4534   req->transKey = m_tx.transKey();
4535   req->requestInfo = offline ? CreateIndxReq::RF_BUILD_OFFLINE : 0;
4536   req->requestInfo |= m_tx.requestFlags();
4537 
4538   Uint32 it = getKernelConstant(impl.m_type,
4539 				indexTypeMapping,
4540 				DictTabInfo::UndefTableType);
4541 
4542   if(it == DictTabInfo::UndefTableType){
4543     m_error.code = 4250;
4544     return -1;
4545   }
4546   req->indexType = it;
4547 
4548   req->tableId = table.m_id;
4549   req->tableVersion = table.m_version;
4550   req->online = true;
4551   IndexAttributeList attributeList;
4552   attributeList.sz = impl.m_columns.size();
4553   for(i = 0; i<attributeList.sz; i++){
4554     const NdbColumnImpl* col =
4555       table.getColumn(impl.m_columns[i]->m_name.c_str());
4556     if(col == 0){
4557       m_error.code = 4247;
4558       return -1;
4559     }
4560     // Copy column definition  XXX must be wrong, overwrites
4561     *impl.m_columns[i] = *col;
4562 
4563     // index key type check
4564     if ((it == DictTabInfo::UniqueHashIndex &&
4565          (err = NdbSqlUtil::check_column_for_hash_index(col->m_type, col->m_cs)))
4566         ||
4567         (it == DictTabInfo::OrderedIndex &&
4568          (err = NdbSqlUtil::check_column_for_ordered_index(col->m_type, col->m_cs))))
4569     {
4570       m_error.code = err;
4571       return -1;
4572     }
4573     // API uses external column number to talk to DICT
4574     attributeList.id[i] = col->m_column_no;
4575   }
4576   LinearSectionPtr ptr[2];
4577   ptr[0].p = (Uint32*)&attributeList;
4578   ptr[0].sz = 1 + attributeList.sz;
4579   ptr[1].p = (Uint32*)m_buffer.get_data();
4580   ptr[1].sz = m_buffer.length() >> 2;                //BUG?
4581 
4582   int errCodes[] = { CreateIndxRef::Busy, CreateIndxRef::NotMaster, 0 };
4583   return dictSignal(&tSignal, ptr, 2,
4584 		    0, // master
4585 		    WAIT_CREATE_INDX_REQ,
4586 		    DICT_WAITFOR_TIMEOUT, 100,
4587 		    errCodes);
4588 }
4589 
4590 void
execCREATE_INDX_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4591 NdbDictInterface::execCREATE_INDX_CONF(const NdbApiSignal * signal,
4592 				       const LinearSectionPtr ptr[3])
4593 {
4594   DBUG_ENTER("NdbDictInterface::execCREATE_INDX_CONF");
4595   m_impl->theWaiter.signal(NO_WAIT);
4596   DBUG_VOID_RETURN;
4597 }
4598 
4599 void
execCREATE_INDX_REF(const NdbApiSignal * sig,const LinearSectionPtr ptr[3])4600 NdbDictInterface::execCREATE_INDX_REF(const NdbApiSignal * sig,
4601 				      const LinearSectionPtr ptr[3])
4602 {
4603   DBUG_ENTER("NdbDictInterface::execCREATE_INDX_REF");
4604   const CreateIndxRef* ref = CAST_CONSTPTR(CreateIndxRef, sig->getDataPtr());
4605   m_error.code = ref->errorCode;
4606   DBUG_PRINT("info", ("Error code = %d", m_error.code));
4607   if (m_error.code == ref->NotMaster)
4608     m_masterNodeId = ref->masterNodeId;
4609   m_impl->theWaiter.signal(NO_WAIT);
4610   DBUG_VOID_RETURN;
4611 }
4612 
4613 // INDEX_STAT
4614 
4615 int
updateIndexStat(const NdbIndexImpl & index,const NdbTableImpl & table)4616 NdbDictionaryImpl::updateIndexStat(const NdbIndexImpl& index,
4617                                    const NdbTableImpl& table)
4618 {
4619   Uint32 rt = IndexStatReq::RT_UPDATE_STAT;
4620   return m_receiver.doIndexStatReq(m_ndb, index, table, rt);
4621 }
4622 
4623 int
updateIndexStat(Uint32 indexId,Uint32 indexVersion,Uint32 tableId)4624 NdbDictionaryImpl::updateIndexStat(Uint32 indexId,
4625                                    Uint32 indexVersion,
4626                                    Uint32 tableId)
4627 {
4628   Uint32 rt = IndexStatReq::RT_UPDATE_STAT;
4629   return m_receiver.doIndexStatReq(m_ndb, indexId, indexVersion, tableId, rt);
4630 }
4631 
4632 int
deleteIndexStat(const NdbIndexImpl & index,const NdbTableImpl & table)4633 NdbDictionaryImpl::deleteIndexStat(const NdbIndexImpl& index,
4634                                    const NdbTableImpl& table)
4635 {
4636   Uint32 rt = IndexStatReq::RT_DELETE_STAT;
4637   return m_receiver.doIndexStatReq(m_ndb, index, table, rt);
4638 }
4639 
4640 int
deleteIndexStat(Uint32 indexId,Uint32 indexVersion,Uint32 tableId)4641 NdbDictionaryImpl::deleteIndexStat(Uint32 indexId,
4642                                    Uint32 indexVersion,
4643                                    Uint32 tableId)
4644 {
4645   Uint32 rt = IndexStatReq::RT_DELETE_STAT;
4646   return m_receiver.doIndexStatReq(m_ndb, indexId, indexVersion, tableId, rt);
4647 }
4648 
4649 int
doIndexStatReq(Ndb & ndb,const NdbIndexImpl & index,const NdbTableImpl & table,Uint32 rt)4650 NdbDictInterface::doIndexStatReq(Ndb& ndb,
4651                                  const NdbIndexImpl& index,
4652                                  const NdbTableImpl& table,
4653                                  Uint32 rt)
4654 {
4655   return doIndexStatReq(ndb, index.m_id, index.m_version, table.m_id, rt);
4656 }
4657 
4658 int
doIndexStatReq(Ndb & ndb,Uint32 indexId,Uint32 indexVersion,Uint32 tableId,Uint32 requestType)4659 NdbDictInterface::doIndexStatReq(Ndb& ndb,
4660                                  Uint32 indexId,
4661                                  Uint32 indexVersion,
4662                                  Uint32 tableId,
4663                                  Uint32 requestType)
4664 {
4665   NdbApiSignal tSignal(m_reference);
4666   tSignal.theReceiversBlockNumber = DBDICT;
4667   tSignal.theVerId_signalNumber = GSN_INDEX_STAT_REQ;
4668   tSignal.theLength = IndexStatReq::SignalLength;
4669 
4670   IndexStatReq* req = CAST_PTR(IndexStatReq, tSignal.getDataPtrSend());
4671   req->clientRef = m_reference;
4672   req->clientData = 0;
4673   req->transId = m_tx.transId();
4674   req->transKey = m_tx.transKey();
4675   req->requestInfo = requestType;
4676   req->requestFlag = 0;
4677   req->indexId = indexId;
4678   req->indexVersion = indexVersion;
4679   req->tableId = tableId;
4680 
4681   int errCodes[] = { IndexStatRef::Busy, IndexStatRef::NotMaster, 0 };
4682   return dictSignal(&tSignal, 0, 0,
4683                     0,
4684                     WAIT_CREATE_INDX_REQ,
4685                     DICT_WAITFOR_TIMEOUT, 100,
4686                     errCodes);
4687 }
4688 
4689 void
execINDEX_STAT_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4690 NdbDictInterface::execINDEX_STAT_CONF(const NdbApiSignal * signal,
4691 				      const LinearSectionPtr ptr[3])
4692 {
4693   DBUG_ENTER("NdbDictInterface::execINDEX_STAT_CONF");
4694   m_impl->theWaiter.signal(NO_WAIT);
4695   DBUG_VOID_RETURN;
4696 }
4697 
4698 void
execINDEX_STAT_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4699 NdbDictInterface::execINDEX_STAT_REF(const NdbApiSignal * signal,
4700 				     const LinearSectionPtr ptr[3])
4701 {
4702   DBUG_ENTER("NdbDictInterface::execINDEX_STAT_REF");
4703   const IndexStatRef* ref = CAST_CONSTPTR(IndexStatRef, signal->getDataPtr());
4704   m_error.code = ref->errorCode;
4705   DBUG_PRINT("info", ("Error code = %d", m_error.code));
4706   if (m_error.code == ref->NotMaster)
4707     m_masterNodeId = ref->masterNodeId;
4708   m_impl->theWaiter.signal(NO_WAIT);
4709   DBUG_VOID_RETURN;
4710 }
4711 
4712 /*****************************************************************
4713  * Drop index
4714  */
4715 int
dropIndex(const char * indexName,const char * tableName)4716 NdbDictionaryImpl::dropIndex(const char * indexName,
4717 			     const char * tableName)
4718 {
4719   return dropIndex(indexName, tableName, false);
4720 }
4721 
4722 int
dropIndex(const char * indexName,const char * tableName,bool ignoreFKs)4723 NdbDictionaryImpl::dropIndex(const char * indexName,
4724 			     const char * tableName,
4725                              bool ignoreFKs)
4726 {
4727   ASSERT_NOT_MYSQLD;
4728   NdbIndexImpl * idx = getIndex(indexName, tableName);
4729   if (idx == 0) {
4730     m_error.code = 4243;
4731     return -1;
4732   }
4733   int ret = dropIndex(*idx, tableName, ignoreFKs);
4734   // If index stored in cache is incompatible with the one in the kernel
4735   // we must clear the cache and try again
4736   if (ret == INCOMPATIBLE_VERSION) {
4737     const BaseString internalIndexName((tableName)
4738       ?
4739       m_ndb.internalize_index_name(getTable(tableName), indexName)
4740       :
4741       m_ndb.internalize_table_name(indexName)); // Index is also a table
4742 
4743     m_localHash.drop(internalIndexName.c_str());
4744     m_globalHash->lock();
4745     m_globalHash->release(idx->m_table, 1);
4746     m_globalHash->unlock();
4747     return dropIndex(indexName, tableName);
4748   }
4749 
4750   return ret;
4751 }
4752 
4753 int
dropIndex(NdbIndexImpl & impl,const char * tableName)4754 NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName)
4755 {
4756   return dropIndex(impl, tableName, false);
4757 }
4758 
4759 int
dropIndex(NdbIndexImpl & impl,const char * tableName,bool ignoreFKs)4760 NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName,
4761                              bool ignoreFKs)
4762 {
4763   const char * indexName = impl.getName();
4764   if (tableName || m_ndb.usingFullyQualifiedNames()) {
4765     NdbTableImpl * timpl = impl.m_table;
4766 
4767     if (timpl == 0) {
4768       m_error.code = 709;
4769       return -1;
4770     }
4771 
4772     const BaseString internalIndexName((tableName)
4773       ?
4774       m_ndb.internalize_index_name(getTable(tableName), indexName)
4775       :
4776       m_ndb.internalize_table_name(indexName)); // Index is also a table
4777 
4778     if(impl.m_status == NdbDictionary::Object::New){
4779       return dropIndex(indexName, tableName, ignoreFKs);
4780     }
4781 
4782     int ret= dropIndexGlobal(impl, ignoreFKs);
4783     if (ret == 0)
4784     {
4785       m_globalHash->lock();
4786       m_globalHash->release(impl.m_table, 1);
4787       m_globalHash->unlock();
4788       m_localHash.drop(internalIndexName.c_str());
4789     }
4790     return ret;
4791   }
4792 
4793   m_error.code = 4243;
4794   return -1;
4795 }
4796 
4797 int
dropIndexGlobal(NdbIndexImpl & impl)4798 NdbDictionaryImpl::dropIndexGlobal(NdbIndexImpl & impl)
4799 {
4800   return dropIndexGlobal(impl, false);
4801 }
4802 
4803 int
dropIndexGlobal(NdbIndexImpl & impl,bool ignoreFKs)4804 NdbDictionaryImpl::dropIndexGlobal(NdbIndexImpl & impl, bool ignoreFKs)
4805 {
4806   DBUG_ENTER("NdbDictionaryImpl::dropIndexGlobal");
4807   const char* index_name = impl.m_internalName.c_str();
4808   DBUG_PRINT("info", ("index name: %s", index_name));
4809 
4810   List list;
4811   if (listDependentObjects(list, impl.m_id) != 0)
4812     ERR_RETURN(getNdbError(), -1);
4813 
4814   if (!ignoreFKs)
4815   {
4816     /* prevent dropping index if used by a FK */
4817     for (unsigned i = 0; i < list.count; i++)
4818     {
4819       const List::Element& element = list.elements[i];
4820       const char* fk_name = element.name;
4821 
4822       if (DictTabInfo::isForeignKey(element.type))
4823       {
4824         NdbDictionary::ForeignKey fk;
4825         DBUG_PRINT("info", ("fk name: %s", fk_name));
4826         if (getForeignKey(fk, fk_name) != 0)
4827         {
4828           ERR_RETURN(getNdbError(), -1);
4829         }
4830 
4831         const char* parent = fk.getParentIndex();
4832         const char* child = fk.getChildIndex();
4833         DBUG_PRINT("info", ("parent index: %s child index: %s",
4834                              parent?parent:"PK", child?child:"PK"));
4835         if (parent != 0 && strcmp(parent, index_name) == 0)
4836         {
4837           m_receiver.m_error.code = 21081;
4838           ERR_RETURN(getNdbError(), -1);
4839         }
4840         if (child != 0 && strcmp(child, index_name) == 0)
4841         {
4842           m_receiver.m_error.code = 21082;
4843           ERR_RETURN(getNdbError(), -1);
4844         }
4845       }
4846     }
4847   }
4848 
4849   int ret = m_receiver.dropIndex(impl, *impl.m_table);
4850   impl.m_status = NdbDictionary::Object::Invalid;
4851   if(ret == 0)
4852   {
4853     DBUG_RETURN(0);
4854   }
4855   ERR_RETURN(getNdbError(), ret);
4856 }
4857 
4858 int
dropIndex(const NdbIndexImpl & impl,const NdbTableImpl & timpl)4859 NdbDictInterface::dropIndex(const NdbIndexImpl & impl,
4860 			    const NdbTableImpl & timpl)
4861 {
4862   DBUG_ENTER("NdbDictInterface::dropIndex");
4863   DBUG_PRINT("enter", ("indexId: %d  indexVersion: %d",
4864                        timpl.m_id, timpl.m_version));
4865   NdbApiSignal tSignal(m_reference);
4866   tSignal.theReceiversBlockNumber = DBDICT;
4867   tSignal.theVerId_signalNumber   = GSN_DROP_INDX_REQ;
4868   tSignal.theLength = DropIndxReq::SignalLength;
4869 
4870   DropIndxReq * const req = CAST_PTR(DropIndxReq, tSignal.getDataPtrSend());
4871   req->clientRef = m_reference;
4872   req->clientData = 0;
4873   req->transId = m_tx.transId();
4874   req->transKey = m_tx.transKey();
4875   req->requestInfo = 0;
4876   req->requestInfo |= m_tx.requestFlags();
4877   req->indexId = timpl.m_id;
4878   req->indexVersion = timpl.m_version;
4879 
4880   int errCodes[] = { DropIndxRef::Busy, DropIndxRef::NotMaster, 0 };
4881   int r = dictSignal(&tSignal, 0, 0,
4882 		     0, // master
4883 		     WAIT_DROP_INDX_REQ,
4884 		     DICT_WAITFOR_TIMEOUT, 100,
4885 		     errCodes);
4886   if(m_error.code == DropIndxRef::InvalidIndexVersion) {
4887     // Clear caches and try again
4888     ERR_RETURN(m_error, INCOMPATIBLE_VERSION);
4889   }
4890   ERR_RETURN(m_error, r);
4891 }
4892 
4893 void
execDROP_INDX_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4894 NdbDictInterface::execDROP_INDX_CONF(const NdbApiSignal * signal,
4895 				       const LinearSectionPtr ptr[3])
4896 {
4897   DBUG_ENTER("NdbDictInterface::DROP_INDX_CONF");
4898   m_impl->theWaiter.signal(NO_WAIT);
4899   DBUG_VOID_RETURN;
4900 }
4901 
4902 void
execDROP_INDX_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])4903 NdbDictInterface::execDROP_INDX_REF(const NdbApiSignal * signal,
4904 				      const LinearSectionPtr ptr[3])
4905 {
4906   DBUG_ENTER("NdbDictInterface::execDROP_INDX_REF");
4907   const DropIndxRef* ref = CAST_CONSTPTR(DropIndxRef, signal->getDataPtr());
4908   m_error.code = ref->errorCode;
4909   DBUG_PRINT("info", ("Error code = %d", m_error.code));
4910   if (m_error.code == ref->NotMaster)
4911     m_masterNodeId = ref->masterNodeId;
4912   m_impl->theWaiter.signal(NO_WAIT);
4913   DBUG_VOID_RETURN;
4914 }
4915 
4916 /*****************************************************************
4917  * Create event
4918  */
4919 
4920 int
createEvent(NdbEventImpl & evnt)4921 NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
4922 {
4923   DBUG_ENTER("NdbDictionaryImpl::createEvent");
4924   int i;
4925   NdbTableImpl* tab= evnt.m_tableImpl;
4926   if (tab == 0)
4927   {
4928     tab= getTable(evnt.getTableName());
4929     if(tab == 0){
4930       DBUG_PRINT("info",("NdbDictionaryImpl::createEvent: table not found: %s",
4931 			 evnt.getTableName()));
4932       ERR_RETURN(getNdbError(), -1);
4933     }
4934     evnt.setTable(tab);
4935   }
4936 
4937   DBUG_PRINT("info",("Table: id: %d version: %d", tab->m_id, tab->m_version));
4938 
4939   NdbTableImpl &table = *evnt.m_tableImpl;
4940 
4941   int attributeList_sz = evnt.m_attrIds.size();
4942 
4943   for (i = 0; i < attributeList_sz; i++) {
4944     NdbColumnImpl *col_impl = table.getColumn(evnt.m_attrIds[i]);
4945     if (col_impl) {
4946       evnt.m_facade->addColumn(*(col_impl->m_facade));
4947     } else {
4948       ndbout_c("Attr id %u in table %s not found", evnt.m_attrIds[i],
4949 	       evnt.getTableName());
4950       m_error.code= 4713;
4951       ERR_RETURN(getNdbError(), -1);
4952     }
4953   }
4954 
4955   evnt.m_attrIds.clear();
4956 
4957   attributeList_sz = evnt.m_columns.size();
4958 
4959   DBUG_PRINT("info",("Event on tableId=%d, tableVersion=%d, event name %s, no of columns %d",
4960 		     table.m_id, table.m_version,
4961 		     evnt.m_name.c_str(),
4962 		     evnt.m_columns.size()));
4963 
4964   int pk_count = 0;
4965   evnt.m_attrListBitmask.clear();
4966 
4967   for(i = 0; i<attributeList_sz; i++){
4968     const NdbColumnImpl* col =
4969       table.getColumn(evnt.m_columns[i]->m_name.c_str());
4970     if(col == 0){
4971       m_error.code= 4247;
4972       ERR_RETURN(getNdbError(), -1);
4973     }
4974     // Copy column definition
4975     *evnt.m_columns[i] = *col;
4976 
4977     if(col->m_pk){
4978       pk_count++;
4979     }
4980 
4981     evnt.m_attrListBitmask.set(col->m_attrId);
4982   }
4983 
4984   // Sort index attributes according to primary table (using insertion sort)
4985   for(i = 1; i < attributeList_sz; i++) {
4986     NdbColumnImpl* temp = evnt.m_columns[i];
4987     unsigned int j = i;
4988     while((j > 0) && (evnt.m_columns[j - 1]->m_attrId > temp->m_attrId)) {
4989       evnt.m_columns[j] = evnt.m_columns[j - 1];
4990       j--;
4991     }
4992     evnt.m_columns[j] = temp;
4993   }
4994   // Check for illegal duplicate attributes
4995   for(i = 1; i<attributeList_sz; i++) {
4996     if (evnt.m_columns[i-1]->m_attrId == evnt.m_columns[i]->m_attrId) {
4997       m_error.code= 4258;
4998       ERR_RETURN(getNdbError(), -1);
4999     }
5000   }
5001 
5002   // NdbDictInterface m_receiver;
5003   if (m_receiver.createEvent(m_ndb, evnt, 0 /* getFlag unset */) != 0)
5004     ERR_RETURN(getNdbError(), -1);
5005 
5006   // Create blob events
5007   if (evnt.m_mergeEvents && createBlobEvents(evnt) != 0) {
5008     int save_code = m_error.code;
5009     (void)dropEvent(evnt.m_name.c_str(), 0);
5010     m_error.code = save_code;
5011     ERR_RETURN(getNdbError(), -1);
5012   }
5013   DBUG_RETURN(0);
5014 }
5015 
5016 int
createBlobEvents(NdbEventImpl & evnt)5017 NdbDictionaryImpl::createBlobEvents(NdbEventImpl& evnt)
5018 {
5019   DBUG_ENTER("NdbDictionaryImpl::createBlobEvents");
5020   NdbTableImpl& t = *evnt.m_tableImpl;
5021   Uint32 n = t.m_noOfBlobs;
5022   Uint32 i;
5023   for (i = 0; i < evnt.m_columns.size() && n > 0; i++) {
5024     NdbColumnImpl & c = *evnt.m_columns[i];
5025     if (! c.getBlobType() || c.getPartSize() == 0)
5026       continue;
5027     n--;
5028     NdbEventImpl blob_evnt;
5029     NdbBlob::getBlobEvent(blob_evnt, &evnt, &c);
5030     if (createEvent(blob_evnt) != 0)
5031       ERR_RETURN(getNdbError(), -1);
5032   }
5033   DBUG_RETURN(0);
5034 }
5035 
5036 int
createEvent(class Ndb & ndb,NdbEventImpl & evnt,int getFlag)5037 NdbDictInterface::createEvent(class Ndb & ndb,
5038 			      NdbEventImpl & evnt,
5039 			      int getFlag)
5040 {
5041   DBUG_ENTER("NdbDictInterface::createEvent");
5042   DBUG_PRINT("enter",("getFlag=%d",getFlag));
5043 
5044   NdbApiSignal tSignal(m_reference);
5045   tSignal.theReceiversBlockNumber = DBDICT;
5046   tSignal.theVerId_signalNumber   = GSN_CREATE_EVNT_REQ;
5047   if (getFlag)
5048     tSignal.theLength = CreateEvntReq::SignalLengthGet;
5049   else
5050     tSignal.theLength = CreateEvntReq::SignalLengthCreate;
5051 
5052   CreateEvntReq * const req = CAST_PTR(CreateEvntReq, tSignal.getDataPtrSend());
5053 
5054   req->setUserRef(m_reference);
5055   req->setUserData(0);
5056 
5057   Uint32 seccnt = 1;
5058   LinearSectionPtr ptr[2];
5059 
5060   if (getFlag) {
5061     // getting event from Dictionary
5062     req->setRequestType(CreateEvntReq::RT_USER_GET);
5063   } else {
5064     DBUG_PRINT("info",("tableId: %u tableVersion: %u",
5065 		       evnt.m_tableImpl->m_id,
5066                        evnt.m_tableImpl->m_version));
5067     // creating event in Dictionary
5068     req->setRequestType(CreateEvntReq::RT_USER_CREATE);
5069     req->setTableId(evnt.m_tableImpl->m_id);
5070     req->setTableVersion(evnt.m_tableImpl->m_version);
5071     req->setAttrListBitmask(evnt.m_attrListBitmask);
5072     req->setEventType(evnt.mi_type);
5073     req->clearFlags();
5074     if (evnt.m_rep & NdbDictionary::Event::ER_ALL)
5075       req->setReportAll();
5076     if (evnt.m_rep & NdbDictionary::Event::ER_SUBSCRIBE)
5077       req->setReportSubscribe();
5078     if (evnt.m_rep & NdbDictionary::Event::ER_DDL)
5079     {
5080       req->setReportDDL();
5081     }
5082     else
5083     {
5084       req->clearReportDDL();
5085     }
5086     ptr[1].p = evnt.m_attrListBitmask.rep.data;
5087     ptr[1].sz = evnt.m_attrListBitmask.getSizeInWords();
5088     seccnt++;
5089   }
5090 
5091   UtilBufferWriter w(m_buffer);
5092 
5093   const size_t len = strlen(evnt.m_name.c_str()) + 1;
5094   if(len > MAX_TAB_NAME_SIZE) {
5095     m_error.code= 4241;
5096     ERR_RETURN(getNdbError(), -1);
5097   }
5098 
5099   w.add(SimpleProperties::StringValue, evnt.m_name.c_str());
5100 
5101   if (getFlag == 0)
5102   {
5103     const BaseString internal_tabname(
5104       ndb.internalize_table_name(evnt.m_tableName.c_str()));
5105     w.add(SimpleProperties::StringValue,
5106 	 internal_tabname.c_str());
5107   }
5108 
5109   ptr[0].p = (Uint32*)m_buffer.get_data();
5110   ptr[0].sz = (m_buffer.length()+3) >> 2;
5111 
5112   int ret = dictSignal(&tSignal,ptr, seccnt,
5113 		       0, // master
5114 		       WAIT_CREATE_INDX_REQ,
5115 		       DICT_WAITFOR_TIMEOUT, 100,
5116 		       0, -1);
5117 
5118   if (ret) {
5119     ERR_RETURN(getNdbError(), ret);
5120   }
5121 
5122   char *dataPtr = (char *)m_buffer.get_data();
5123   unsigned int lenCreateEvntConf = *((unsigned int *)dataPtr);
5124   dataPtr += sizeof(lenCreateEvntConf);
5125   CreateEvntConf const * evntConf = (CreateEvntConf *)dataPtr;
5126   dataPtr += lenCreateEvntConf;
5127 
5128   //  NdbEventImpl *evntImpl = (NdbEventImpl *)evntConf->getUserData();
5129 
5130   evnt.m_eventId = evntConf->getEventId();
5131   evnt.m_eventKey = evntConf->getEventKey();
5132   evnt.m_table_id = evntConf->getTableId();
5133   evnt.m_table_version = evntConf->getTableVersion();
5134 
5135   if (getFlag) {
5136     evnt.m_attrListBitmask = evntConf->getAttrListBitmask();
5137     evnt.mi_type           = evntConf->getEventType();
5138     evnt.setTable(dataPtr);
5139     if (!m_tableData.empty())
5140     {
5141       Uint32 len = m_tableData.length();
5142       assert((len & 3) == 0);
5143       len /= 4;
5144       if (len <= evnt.m_attrListBitmask.getSizeInWords())
5145       {
5146         evnt.m_attrListBitmask.clear();
5147         memcpy(evnt.m_attrListBitmask.rep.data, m_tableData.get_data(), 4*len);
5148       }
5149       else
5150       {
5151         memcpy(evnt.m_attrListBitmask.rep.data, m_tableData.get_data(),
5152                4*evnt.m_attrListBitmask.getSizeInWords());
5153       }
5154     }
5155   } else {
5156     if ((Uint32) evnt.m_tableImpl->m_id         != evntConf->getTableId() ||
5157 	evnt.m_tableImpl->m_version    != evntConf->getTableVersion() ||
5158 	//evnt.m_attrListBitmask != evntConf->getAttrListBitmask() ||
5159 	evnt.mi_type           != evntConf->getEventType()) {
5160       ndbout_c("ERROR*************");
5161       m_buffer.clear();
5162       m_tableData.clear();
5163       ERR_RETURN(getNdbError(), 1);
5164     }
5165   }
5166 
5167   m_buffer.clear();
5168   m_tableData.clear();
5169 
5170   DBUG_RETURN(0);
5171 }
5172 
5173 int
executeSubscribeEvent(NdbEventOperationImpl & ev_op)5174 NdbDictionaryImpl::executeSubscribeEvent(NdbEventOperationImpl & ev_op)
5175 {
5176   // NdbDictInterface m_receiver;
5177   return m_receiver.executeSubscribeEvent(m_ndb, ev_op);
5178 }
5179 
5180 int
executeSubscribeEvent(class Ndb & ndb,NdbEventOperationImpl & ev_op)5181 NdbDictInterface::executeSubscribeEvent(class Ndb & ndb,
5182 					NdbEventOperationImpl & ev_op)
5183 {
5184   DBUG_ENTER("NdbDictInterface::executeSubscribeEvent");
5185   NdbApiSignal tSignal(m_reference);
5186   tSignal.theReceiversBlockNumber = DBDICT;
5187   tSignal.theVerId_signalNumber   = GSN_SUB_START_REQ;
5188   tSignal.theLength = SubStartReq::SignalLength;
5189 
5190   SubStartReq * req = CAST_PTR(SubStartReq, tSignal.getDataPtrSend());
5191 
5192   req->subscriptionId   = ev_op.m_eventImpl->m_eventId;
5193   req->subscriptionKey  = ev_op.m_eventImpl->m_eventKey;
5194   req->part             = SubscriptionData::TableData;
5195   req->subscriberData   = ev_op.m_oid;
5196   req->subscriberRef    = m_reference;
5197 
5198   DBUG_PRINT("info",("GSN_SUB_START_REQ subscriptionId=%d,subscriptionKey=%d,"
5199 		     "subscriberData=%d",req->subscriptionId,
5200 		     req->subscriptionKey,req->subscriberData));
5201 
5202   int errCodes[] = { SubStartRef::Busy,
5203                      SubStartRef::BusyWithNR,
5204                      SubStartRef::NotMaster,
5205                      0 };
5206   int ret = dictSignal(&tSignal,NULL,0,
5207                        0 /*use masternode id*/,
5208                        WAIT_CREATE_INDX_REQ /*WAIT_CREATE_EVNT_REQ*/,
5209                        -1, 100,
5210                        errCodes, -1);
5211 
5212   DBUG_RETURN(ret);
5213 }
5214 
5215 int
stopSubscribeEvent(NdbEventOperationImpl & ev_op)5216 NdbDictionaryImpl::stopSubscribeEvent(NdbEventOperationImpl & ev_op)
5217 {
5218   // NdbDictInterface m_receiver;
5219   return m_receiver.stopSubscribeEvent(m_ndb, ev_op);
5220 }
5221 
5222 int
stopSubscribeEvent(class Ndb & ndb,NdbEventOperationImpl & ev_op)5223 NdbDictInterface::stopSubscribeEvent(class Ndb & ndb,
5224 				     NdbEventOperationImpl & ev_op)
5225 {
5226   DBUG_ENTER("NdbDictInterface::stopSubscribeEvent");
5227 
5228   NdbApiSignal tSignal(m_reference);
5229   //  tSignal.theReceiversBlockNumber = SUMA;
5230   tSignal.theReceiversBlockNumber = DBDICT;
5231   tSignal.theVerId_signalNumber   = GSN_SUB_STOP_REQ;
5232   tSignal.theLength = SubStopReq::SignalLength;
5233 
5234   SubStopReq * req = CAST_PTR(SubStopReq, tSignal.getDataPtrSend());
5235 
5236   req->subscriptionId  = ev_op.m_eventImpl->m_eventId;
5237   req->subscriptionKey = ev_op.m_eventImpl->m_eventKey;
5238   req->subscriberData  = ev_op.m_oid;
5239   req->part            = (Uint32) SubscriptionData::TableData;
5240   req->subscriberRef   = m_reference;
5241   req->requestInfo     = 0;
5242 
5243   DBUG_PRINT("info",("GSN_SUB_STOP_REQ subscriptionId=%d,subscriptionKey=%d,"
5244 		     "subscriberData=%d",req->subscriptionId,
5245 		     req->subscriptionKey,req->subscriberData));
5246 
5247   int errCodes[] = { SubStartRef::Busy,
5248                      SubStartRef::BusyWithNR,
5249                      SubStartRef::NotMaster,
5250                      0 };
5251   int ret= dictSignal(&tSignal,NULL,0,
5252                       0 /*use masternode id*/,
5253                       WAIT_CREATE_INDX_REQ /*WAIT_SUB_STOP__REQ*/,
5254                       -1, 100,
5255                       errCodes, -1);
5256   if (ret == 0)
5257   {
5258     Uint32 *data = (Uint32*)m_buffer.get_data();
5259     ev_op.m_stop_gci = data[1] | (Uint64(data[0]) << 32);
5260   }
5261   DBUG_RETURN(ret);
5262 }
5263 
5264 NdbEventImpl *
getEvent(const char * eventName,NdbTableImpl * tab)5265 NdbDictionaryImpl::getEvent(const char * eventName, NdbTableImpl* tab)
5266 {
5267   DBUG_ENTER("NdbDictionaryImpl::getEvent");
5268   DBUG_PRINT("enter",("eventName= %s", eventName));
5269 
5270   NdbEventImpl *ev =  new NdbEventImpl();
5271   if (ev == NULL) {
5272     DBUG_RETURN(NULL);
5273   }
5274 
5275   ev->setName(eventName);
5276 
5277   int ret = m_receiver.createEvent(m_ndb, *ev, 1 /* getFlag set */);
5278 
5279   if (ret) {
5280     delete ev;
5281     DBUG_RETURN(NULL);
5282   }
5283 
5284   // We only have the table name with internal name
5285   DBUG_PRINT("info",("table %s", ev->getTableName()));
5286   if (tab == NULL)
5287   {
5288     tab= fetchGlobalTableImplRef(InitTable(ev->getTableName()));
5289     if (tab == 0)
5290     {
5291       DBUG_PRINT("error",("unable to find table %s", ev->getTableName()));
5292       delete ev;
5293       DBUG_RETURN(NULL);
5294     }
5295     if ((tab->m_status != NdbDictionary::Object::Retrieved) ||
5296         ((Uint32) tab->m_id != ev->m_table_id) ||
5297         (table_version_major(tab->m_version) !=
5298          table_version_major(ev->m_table_version)))
5299     {
5300       DBUG_PRINT("info", ("mismatch on verison in cache"));
5301       releaseTableGlobal(*tab, 1);
5302       tab= fetchGlobalTableImplRef(InitTable(ev->getTableName()));
5303       if (tab == 0)
5304       {
5305         DBUG_PRINT("error",("unable to find table %s", ev->getTableName()));
5306         delete ev;
5307         DBUG_RETURN(NULL);
5308       }
5309     }
5310     ev->setTable(tab);
5311     releaseTableGlobal(*tab, 0);
5312   }
5313   else
5314     ev->setTable(tab);
5315   tab = 0;
5316 
5317   ev->setTable(m_ndb.externalizeTableName(ev->getTableName()));
5318   // get the columns from the attrListBitmask
5319   NdbTableImpl &table = *ev->m_tableImpl;
5320   AttributeMask & mask = ev->m_attrListBitmask;
5321   unsigned attributeList_sz = mask.count();
5322 
5323   DBUG_PRINT("info",("Table: id: %d version: %d",
5324                      table.m_id, table.m_version));
5325 
5326   if ((Uint32) table.m_id != ev->m_table_id ||
5327       table_version_major(table.m_version) !=
5328       table_version_major(ev->m_table_version))
5329   {
5330     m_error.code = 241;
5331     delete ev;
5332     DBUG_RETURN(NULL);
5333   }
5334 
5335   if ( attributeList_sz > (uint) table.getNoOfColumns() )
5336   {
5337     m_error.code = 241;
5338     DBUG_PRINT("error",("Invalid version, too many columns"));
5339     delete ev;
5340     DBUG_RETURN(NULL);
5341   }
5342 
5343   assert( (int)attributeList_sz <= table.getNoOfColumns() );
5344   for(unsigned id= 0; ev->m_columns.size() < attributeList_sz; id++) {
5345     if ( id >= (uint) table.getNoOfColumns())
5346     {
5347       m_error.code = 241;
5348       DBUG_PRINT("error",("Invalid version, column %d out of range", id));
5349       delete ev;
5350       DBUG_RETURN(NULL);
5351     }
5352     if (!mask.get(id))
5353       continue;
5354 
5355     const NdbColumnImpl* col = table.getColumn(id);
5356     DBUG_PRINT("info",("column %d %s", id, col->getName()));
5357     NdbColumnImpl* new_col = new NdbColumnImpl;
5358     // Copy column definition
5359     *new_col = *col;
5360     ev->m_columns.push_back(new_col);
5361   }
5362   DBUG_RETURN(ev);
5363 }
5364 
5365 // ev is main event and has been retrieved previously
5366 NdbEventImpl *
getBlobEvent(const NdbEventImpl & ev,uint col_no)5367 NdbDictionaryImpl::getBlobEvent(const NdbEventImpl& ev, uint col_no)
5368 {
5369   DBUG_ENTER("NdbDictionaryImpl::getBlobEvent");
5370   DBUG_PRINT("enter", ("ev=%s col=%u", ev.m_name.c_str(), col_no));
5371 
5372   NdbTableImpl* tab = ev.m_tableImpl;
5373   assert(tab != NULL && col_no < tab->m_columns.size());
5374   NdbColumnImpl* col = tab->m_columns[col_no];
5375   assert(col != NULL && col->getBlobType() && col->getPartSize() != 0);
5376   NdbTableImpl* blob_tab = col->m_blobTable;
5377   assert(blob_tab != NULL);
5378   char bename[MAX_TAB_NAME_SIZE];
5379   NdbBlob::getBlobEventName(bename, &ev, col);
5380 
5381   NdbEventImpl* blob_ev = getEvent(bename, blob_tab);
5382   DBUG_RETURN(blob_ev);
5383 }
5384 
5385 void
execCREATE_EVNT_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5386 NdbDictInterface::execCREATE_EVNT_CONF(const NdbApiSignal * signal,
5387 				       const LinearSectionPtr ptr[3])
5388 {
5389   DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_CONF");
5390 
5391   m_buffer.clear();
5392   m_tableData.clear();
5393   unsigned int len = signal->getLength() << 2;
5394   m_buffer.append((char *)&len, sizeof(len));
5395   m_buffer.append(signal->getDataPtr(), len);
5396 
5397   if (signal->m_noOfSections > 0) {
5398     m_buffer.append((char *)ptr[0].p, strlen((char *)ptr[0].p)+1);
5399   }
5400   if (signal->m_noOfSections > 1)
5401   {
5402     m_tableData.append(ptr[1].p, 4 * ptr[1].sz);
5403   }
5404 
5405 #ifdef DEBUG_OUTPUT
5406   const CreateEvntConf * const createEvntConf=
5407     CAST_CONSTPTR(CreateEvntConf, signal->getDataPtr());
5408 
5409   DBUG_PRINT("info",("nodeid=%d,subscriptionId=%d,subscriptionKey=%d",
5410 		     refToNode(signal->theSendersBlockRef),
5411 		     createEvntConf->getEventId(),
5412                      createEvntConf->getEventKey()));
5413 #endif
5414   m_impl->theWaiter.signal(NO_WAIT);
5415   DBUG_VOID_RETURN;
5416 }
5417 
5418 void
execCREATE_EVNT_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5419 NdbDictInterface::execCREATE_EVNT_REF(const NdbApiSignal * signal,
5420 				      const LinearSectionPtr ptr[3])
5421 {
5422   DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_REF");
5423 
5424   const CreateEvntRef* const ref=
5425     CAST_CONSTPTR(CreateEvntRef, signal->getDataPtr());
5426   m_error.code= ref->getErrorCode();
5427   DBUG_PRINT("error",("error=%d,line=%d,node=%d",ref->getErrorCode(),
5428 		      ref->getErrorLine(),ref->getErrorNode()));
5429   if (m_error.code == CreateEvntRef::NotMaster)
5430     m_masterNodeId = ref->getMasterNode();
5431   m_impl->theWaiter.signal(NO_WAIT);
5432   DBUG_VOID_RETURN;
5433 }
5434 
5435 void
execSUB_STOP_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5436 NdbDictInterface::execSUB_STOP_CONF(const NdbApiSignal * signal,
5437 				      const LinearSectionPtr ptr[3])
5438 {
5439   DBUG_ENTER("NdbDictInterface::execSUB_STOP_CONF");
5440   const SubStopConf * const subStopConf=
5441     CAST_CONSTPTR(SubStopConf, signal->getDataPtr());
5442   const Uint32 sigLen = signal->getLength();
5443 
5444   DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
5445 		     subStopConf->subscriptionId,
5446                      subStopConf->subscriptionKey,
5447                      subStopConf->subscriberData));
5448 
5449   Uint32 gci_hi= 0;
5450   Uint32 gci_lo= 0;
5451   if (SubStopConf::SignalLength >= SubStopConf::SignalLengthWithGci)
5452   {
5453     gci_hi= subStopConf->gci_hi;
5454     gci_lo= subStopConf->gci_lo;
5455   }
5456 
5457   m_buffer.grow(4 * 2); // 2 words
5458   Uint32* data = (Uint32*)m_buffer.get_data();
5459   data[0] = gci_hi;
5460   data[1] = gci_lo;
5461 
5462   /*
5463    * If this is the last subscription stopped NdbEventBuffer needs
5464    * to be notified.  NdbEventBuffer will clear eventbuffer and
5465    * start ignoring Suma signals such as SUB_GCP_COMPLETE_REP.
5466    */
5467   m_impl->m_ndb.theEventBuffer->execSUB_STOP_CONF(subStopConf, sigLen);
5468   m_impl->theWaiter.signal(NO_WAIT);
5469   DBUG_VOID_RETURN;
5470 }
5471 
5472 void
execSUB_STOP_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5473 NdbDictInterface::execSUB_STOP_REF(const NdbApiSignal * signal,
5474 				     const LinearSectionPtr ptr[3])
5475 {
5476   DBUG_ENTER("NdbDictInterface::execSUB_STOP_REF");
5477   const SubStopRef * const subStopRef=
5478     CAST_CONSTPTR(SubStopRef, signal->getDataPtr());
5479   const Uint32 sigLen = signal->getLength();
5480 
5481   m_error.code= subStopRef->errorCode;
5482 
5483   DBUG_PRINT("error",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d,error=%d",
5484 		      subStopRef->subscriptionId,
5485                       subStopRef->subscriptionKey,
5486                       subStopRef->subscriberData,
5487                       m_error.code));
5488   if (m_error.code == SubStopRef::NotMaster &&
5489       signal->getLength() >= SubStopRef::SL_MasterNode)
5490   {
5491     m_masterNodeId = subStopRef->m_masterNodeId;
5492   }
5493   /*
5494    * If this is the last subscription stopped NdbEventBuffer needs
5495    * to be notified.  NdbEventBuffer will clear eventbuffer and
5496    * start ignoring Suma signals such as SUB_GCP_COMPLETE_REP.
5497    */
5498   m_impl->m_ndb.theEventBuffer->execSUB_STOP_REF(subStopRef, sigLen);
5499   m_impl->theWaiter.signal(NO_WAIT);
5500   DBUG_VOID_RETURN;
5501 }
5502 
5503 void
execSUB_START_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5504 NdbDictInterface::execSUB_START_CONF(const NdbApiSignal * signal,
5505 				     const LinearSectionPtr ptr[3])
5506 {
5507   DBUG_ENTER("NdbDictInterface::execSUB_START_CONF");
5508   const SubStartConf * const subStartConf=
5509     CAST_CONSTPTR(SubStartConf, signal->getDataPtr());
5510   const Uint32 sigLen = signal->getLength();
5511 
5512   SubscriptionData::Part part =
5513     (SubscriptionData::Part)subStartConf->part;
5514 
5515   switch(part) {
5516   case SubscriptionData::MetaData: {
5517     DBUG_PRINT("error",("SubscriptionData::MetaData"));
5518     m_error.code= 1;
5519     break;
5520   }
5521   case SubscriptionData::TableData: {
5522     DBUG_PRINT("info",("SubscriptionData::TableData"));
5523     break;
5524   }
5525   default: {
5526     DBUG_PRINT("error",("wrong data"));
5527     m_error.code= 2;
5528     break;
5529   }
5530   }
5531 
5532   DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
5533 		     subStartConf->subscriptionId,
5534                      subStartConf->subscriptionKey,
5535                      subStartConf->subscriberData));
5536   /*
5537    * If this is the first subscription NdbEventBuffer needs to be
5538    * notified.  NdbEventBuffer will start listen to Suma signals
5539    * such as SUB_GCP_COMPLETE_REP.  Also NdbEventBuffer will use
5540    * the total bucket count from signal.
5541    */
5542   m_impl->m_ndb.theEventBuffer->execSUB_START_CONF(subStartConf, sigLen);
5543   m_impl->theWaiter.signal(NO_WAIT);
5544   DBUG_VOID_RETURN;
5545 }
5546 
5547 void
execSUB_START_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5548 NdbDictInterface::execSUB_START_REF(const NdbApiSignal * signal,
5549 				    const LinearSectionPtr ptr[3])
5550 {
5551   DBUG_ENTER("NdbDictInterface::execSUB_START_REF");
5552   const SubStartRef * const subStartRef=
5553     CAST_CONSTPTR(SubStartRef, signal->getDataPtr());
5554   m_error.code= subStartRef->errorCode;
5555   DBUG_PRINT("info", ("Error code = %d", m_error.code));
5556   if (m_error.code == SubStartRef::NotMaster)
5557     m_masterNodeId = subStartRef->m_masterNodeId;
5558   m_impl->theWaiter.signal(NO_WAIT);
5559   DBUG_VOID_RETURN;
5560 }
5561 
5562 /*****************************************************************
5563  * Drop event
5564  */
5565 int
dropEvent(const char * eventName,int force)5566 NdbDictionaryImpl::dropEvent(const char * eventName, int force)
5567 {
5568   DBUG_ENTER("NdbDictionaryImpl::dropEvent");
5569   DBUG_PRINT("enter", ("name:%s  force: %d", eventName, force));
5570 
5571   NdbEventImpl *evnt = NULL;
5572   if (!force)
5573   {
5574     evnt = getEvent(eventName); // allocated
5575     if (evnt == NULL)
5576     {
5577       if (m_error.code != 723 && // no such table
5578           m_error.code != 241)   // invalid table
5579       {
5580         DBUG_PRINT("info", ("no table err=%d", m_error.code));
5581         DBUG_RETURN(-1);
5582       }
5583       DBUG_PRINT("info", ("no table err=%d, drop by name alone", m_error.code));
5584     }
5585   }
5586   if (evnt == NULL)
5587   {
5588     evnt = new NdbEventImpl();
5589     evnt->setName(eventName);
5590   }
5591   int ret = dropEvent(*evnt);
5592   delete evnt;
5593   DBUG_RETURN(ret);
5594 }
5595 
5596 int
dropEvent(const NdbEventImpl & evnt)5597 NdbDictionaryImpl::dropEvent(const NdbEventImpl& evnt)
5598 {
5599   if (dropBlobEvents(evnt) != 0)
5600     return -1;
5601   if (m_receiver.dropEvent(evnt) != 0)
5602     return -1;
5603   return 0;
5604 }
5605 
5606 int
dropBlobEvents(const NdbEventImpl & evnt)5607 NdbDictionaryImpl::dropBlobEvents(const NdbEventImpl& evnt)
5608 {
5609   DBUG_ENTER("NdbDictionaryImpl::dropBlobEvents");
5610   if (evnt.m_tableImpl != 0) {
5611     const NdbTableImpl& t = *evnt.m_tableImpl;
5612     Uint32 n = t.m_noOfBlobs;
5613     Uint32 i;
5614     for (i = 0; i < evnt.m_columns.size() && n > 0; i++) {
5615       const NdbColumnImpl& c = *evnt.m_columns[i];
5616       if (! c.getBlobType() || c.getPartSize() == 0)
5617         continue;
5618       n--;
5619       NdbEventImpl* blob_evnt = getBlobEvent(evnt, i);
5620       if (blob_evnt == NULL)
5621         continue;
5622       (void)dropEvent(*blob_evnt);
5623       delete blob_evnt;
5624     }
5625   }
5626   else
5627   {
5628     DBUG_PRINT("info", ("no table definition, listing events"));
5629     char bename[MAX_TAB_NAME_SIZE];
5630     int val;
5631     // XXX should get name from NdbBlob
5632     sprintf(bename, "NDB$BLOBEVENT_%s_%s", evnt.getName(), "%d");
5633     List list;
5634     if (listEvents(list))
5635       DBUG_RETURN(-1);
5636     for (unsigned i = 0; i < list.count; i++)
5637     {
5638       NdbDictionary::Dictionary::List::Element& elt = list.elements[i];
5639       switch (elt.type)
5640       {
5641       case NdbDictionary::Object::TableEvent:
5642         if (sscanf(elt.name, bename, &val) == 1)
5643         {
5644           DBUG_PRINT("info", ("found blob event %s, removing...", elt.name));
5645           NdbEventImpl* bevnt = new NdbEventImpl();
5646           bevnt->setName(elt.name);
5647           (void)m_receiver.dropEvent(*bevnt);
5648           delete bevnt;
5649         }
5650         else
5651           DBUG_PRINT("info", ("found event %s, skipping...", elt.name));
5652         break;
5653       default:
5654         break;
5655       }
5656     }
5657   }
5658   DBUG_RETURN(0);
5659 }
5660 
5661 int
dropEvent(const NdbEventImpl & evnt)5662 NdbDictInterface::dropEvent(const NdbEventImpl &evnt)
5663 {
5664   NdbApiSignal tSignal(m_reference);
5665   tSignal.theReceiversBlockNumber = DBDICT;
5666   tSignal.theVerId_signalNumber   = GSN_DROP_EVNT_REQ;
5667   tSignal.theLength = DropEvntReq::SignalLength;
5668 
5669   DropEvntReq * const req = CAST_PTR(DropEvntReq, tSignal.getDataPtrSend());
5670 
5671   req->setUserRef(m_reference);
5672   req->setUserData(0);
5673 
5674   UtilBufferWriter w(m_buffer);
5675 
5676   w.add(SimpleProperties::StringValue, evnt.m_name.c_str());
5677 
5678   LinearSectionPtr ptr[1];
5679   ptr[0].p = (Uint32*)m_buffer.get_data();
5680   ptr[0].sz = (m_buffer.length()+3) >> 2;
5681 
5682   return dictSignal(&tSignal,ptr, 1,
5683 		    0 /*use masternode id*/,
5684 		    WAIT_CREATE_INDX_REQ,
5685 		    -1, 100,
5686 		    0, -1);
5687 }
5688 
5689 void
execDROP_EVNT_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5690 NdbDictInterface::execDROP_EVNT_CONF(const NdbApiSignal * signal,
5691 				     const LinearSectionPtr ptr[3])
5692 {
5693   DBUG_ENTER("NdbDictInterface::execDROP_EVNT_CONF");
5694   m_impl->theWaiter.signal(NO_WAIT);
5695   DBUG_VOID_RETURN;
5696 }
5697 
5698 void
execDROP_EVNT_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])5699 NdbDictInterface::execDROP_EVNT_REF(const NdbApiSignal * signal,
5700 				    const LinearSectionPtr ptr[3])
5701 {
5702   DBUG_ENTER("NdbDictInterface::execDROP_EVNT_REF");
5703   const DropEvntRef* const ref=
5704     CAST_CONSTPTR(DropEvntRef, signal->getDataPtr());
5705   m_error.code= ref->getErrorCode();
5706 
5707   DBUG_PRINT("info",("ErrorCode=%u Errorline=%u ErrorNode=%u",
5708 	     ref->getErrorCode(), ref->getErrorLine(), ref->getErrorNode()));
5709   if (m_error.code == DropEvntRef::NotMaster)
5710     m_masterNodeId = ref->getMasterNode();
5711   m_impl->theWaiter.signal(NO_WAIT);
5712   DBUG_VOID_RETURN;
5713 }
5714 
scanEventTable(Ndb * pNdb,const NdbDictionary::Table * pTab,NdbDictionary::Dictionary::List & list)5715 static int scanEventTable(Ndb* pNdb,
5716                           const NdbDictionary::Table* pTab,
5717                           NdbDictionary::Dictionary::List &list)
5718 {
5719   int                  retryAttempt = 0;
5720   const int            retryMax = 100;
5721   NdbTransaction       *pTrans = NULL;
5722   NdbScanOperation     *pOp = NULL;
5723   NdbRecAttr *event_name, *event_id;
5724   NdbError err;
5725   const Uint32 codeWords= 1;
5726   Uint32 codeSpace[ codeWords ];
5727   NdbInterpretedCode code(pTab,
5728                           &codeSpace[0],
5729                           codeWords);
5730   if ((code.interpret_exit_last_row() != 0) ||
5731       (code.finalise() != 0))
5732   {
5733     return code.getNdbError().code;
5734   }
5735 
5736   while (true)
5737   {
5738     NdbDictionary::Dictionary::List tmp_list;
5739 
5740     if (retryAttempt)
5741     {
5742       if (retryAttempt >= retryMax)
5743       {
5744         ndbout << "ERROR: has retried this operation " << retryAttempt
5745                << " times, failing!" << endl;
5746         goto error;
5747       }
5748       if (pTrans)
5749         pNdb->closeTransaction(pTrans);
5750       NdbSleep_MilliSleep(50);
5751     }
5752     retryAttempt++;
5753     pTrans = pNdb->startTransaction();
5754     if (pTrans == NULL)
5755     {
5756       if (pNdb->getNdbError().status == NdbError::TemporaryError)
5757         continue;
5758       goto error;
5759     }
5760 
5761     Uint64 row_count = 0;
5762     {
5763       if ((pOp = pTrans->getNdbScanOperation(pTab)) == NULL)
5764         goto error;
5765       if (pOp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 1) != 0)
5766         goto error;
5767       if (pOp->setInterpretedCode(&code) != 0)
5768         goto error;
5769 
5770       Uint64 tmp;
5771       pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&tmp);
5772       if (pTrans->execute(NdbTransaction::NoCommit) == -1)
5773         goto error;
5774 
5775       int eof;
5776       while ((eof = pOp->nextResult(true)) == 0)
5777         row_count += tmp;
5778 
5779       if (eof == -1)
5780       {
5781         if (pTrans->getNdbError().status == NdbError::TemporaryError)
5782           continue;
5783         goto error;
5784       }
5785     }
5786 
5787     if ((pOp = pTrans->getNdbScanOperation(pTab)) == NULL)
5788       goto error;
5789 
5790     if (pOp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 1) != 0)
5791       goto error;
5792 
5793     if ((event_id   = pOp->getValue(6)) == 0 ||
5794         (event_name = pOp->getValue(0u)) == 0)
5795       goto error;
5796 
5797     if (pTrans->execute(NdbTransaction::NoCommit) == -1)
5798     {
5799       const NdbError err = pTrans->getNdbError();
5800       if (err.status == NdbError::TemporaryError)
5801         continue;
5802       goto error;
5803     }
5804 
5805     /* Cannot handle > 2^32 yet (limit on tmp_list.count is unsigned int) */
5806     assert((row_count & 0xffffffff) == row_count);
5807 
5808     tmp_list.count = (unsigned int)row_count;
5809     tmp_list.elements =
5810       new NdbDictionary::Dictionary::List::Element[(unsigned int)row_count];
5811 
5812     int eof;
5813     unsigned rows = 0;
5814     while((eof = pOp->nextResult()) == 0)
5815     {
5816       if (rows < tmp_list.count)
5817       {
5818         NdbDictionary::Dictionary::List::Element &el = tmp_list.elements[rows];
5819         el.id = event_id->u_32_value();
5820         el.type = NdbDictionary::Object::TableEvent;
5821         el.state = NdbDictionary::Object::StateOnline;
5822         el.store = NdbDictionary::Object::StorePermanent;
5823         Uint32 len = (Uint32)strlen(event_name->aRef());
5824         el.name = new char[len+1];
5825         memcpy(el.name, event_name->aRef(), len);
5826         el.name[len] = 0;
5827       }
5828       rows++;
5829     }
5830     if (eof == -1)
5831     {
5832       if (pTrans->getNdbError().status == NdbError::TemporaryError)
5833         continue;
5834       goto error;
5835     }
5836 
5837     pNdb->closeTransaction(pTrans);
5838 
5839     if (rows < tmp_list.count)
5840       tmp_list.count = rows;
5841 
5842     list = tmp_list;
5843     tmp_list.count = 0;
5844     tmp_list.elements = NULL;
5845 
5846     return 0;
5847   }
5848 error:
5849   int error_code;
5850   if (pTrans)
5851   {
5852     error_code = pTrans->getNdbError().code;
5853     pNdb->closeTransaction(pTrans);
5854   }
5855   else
5856     error_code = pNdb->getNdbError().code;
5857 
5858   return error_code;
5859 }
5860 
5861 int
listEvents(List & list)5862 NdbDictionaryImpl::listEvents(List& list)
5863 {
5864   int error_code;
5865 
5866   BaseString currentDb(m_ndb.getDatabaseName());
5867   BaseString currentSchema(m_ndb.getDatabaseSchemaName());
5868 
5869   m_ndb.setDatabaseName("sys");
5870   m_ndb.setDatabaseSchemaName("def");
5871   {
5872     const NdbDictionary::Table* pTab =
5873       m_facade->getTableGlobal("NDB$EVENTS_0");
5874 
5875     if(pTab == NULL)
5876       error_code = m_facade->getNdbError().code;
5877     else
5878     {
5879       error_code = scanEventTable(&m_ndb, pTab, list);
5880       m_facade->removeTableGlobal(*pTab, 0);
5881     }
5882   }
5883 
5884   m_ndb.setDatabaseName(currentDb.c_str());
5885   m_ndb.setDatabaseSchemaName(currentSchema.c_str());
5886   if (error_code)
5887   {
5888     m_error.code = error_code;
5889     return -1;
5890   }
5891   return 0;
5892 }
5893 
5894 /*****************************************************************
5895  * List objects or indexes
5896  */
5897 int
listObjects(List & list,NdbDictionary::Object::Type type,bool fullyQualified)5898 NdbDictionaryImpl::listObjects(List& list,
5899                                NdbDictionary::Object::Type type,
5900                                bool fullyQualified)
5901 {
5902   int ret;
5903   List list1, list2;
5904   if (type == NdbDictionary::Object::TableEvent)
5905     return listEvents(list);
5906 
5907   if (type == NdbDictionary::Object::TypeUndefined)
5908   {
5909     ret = listEvents(list2);
5910     if (ret)
5911       return ret;
5912   }
5913 
5914   ListTablesReq req;
5915   req.init();
5916   req.setTableId(0);
5917   req.setTableType(getKernelConstant(type, objectTypeMapping, 0));
5918   req.setListNames(true);
5919   if (!list2.count)
5920     return m_receiver.listObjects(list, req, fullyQualified);
5921   ret = m_receiver.listObjects(list1, req, fullyQualified);
5922   if (ret)
5923     return ret;
5924   list.count = list1.count + list2.count;
5925   list.elements = new NdbDictionary::Dictionary::List::Element[list.count];
5926   unsigned i;
5927   const NdbDictionary::Dictionary::List::Element null_el;
5928   for (i = 0; i < list1.count; i++)
5929   {
5930     NdbDictionary::Dictionary::List::Element &el = list1.elements[i];
5931     list.elements[i] = el;
5932     el = null_el;
5933   }
5934   for (i = 0; i < list2.count; i++)
5935   {
5936     NdbDictionary::Dictionary::List::Element &el = list2.elements[i];
5937     list.elements[i + list1.count] = el;
5938     el = null_el;
5939   }
5940   return 0;
5941 }
5942 
5943 int
listIndexes(List & list,Uint32 indexId)5944 NdbDictionaryImpl::listIndexes(List& list, Uint32 indexId)
5945 {
5946   ListTablesReq req;
5947   req.init();
5948   req.setTableId(indexId);
5949   req.setTableType(0);
5950   req.setListNames(true);
5951   req.setListIndexes(true);
5952   return m_receiver.listObjects(list, req, m_ndb.usingFullyQualifiedNames());
5953 }
5954 
5955 int
listDependentObjects(List & list,Uint32 tableId)5956 NdbDictionaryImpl::listDependentObjects(List& list, Uint32 tableId)
5957 {
5958   ListTablesReq req;
5959   req.init();
5960   req.setTableId(tableId);
5961   req.setTableType(0);
5962   req.setListNames(true);
5963   req.setListDependent(true);
5964   return m_receiver.listObjects(list, req, m_ndb.usingFullyQualifiedNames());
5965 }
5966 
5967 int
listObjects(NdbDictionary::Dictionary::List & list,ListTablesReq & ltreq,bool fullyQualifiedNames)5968 NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list,
5969                               ListTablesReq& ltreq, bool fullyQualifiedNames)
5970 {
5971   bool listTablesLongSignal = false;
5972   NdbApiSignal tSignal(m_reference);
5973   ListTablesReq* const req = CAST_PTR(ListTablesReq, tSignal.getDataPtrSend());
5974   memcpy(req, &ltreq, sizeof(ListTablesReq));
5975   req->senderRef = m_reference;
5976   req->senderData = 0;
5977   if (ltreq.getTableId() > 4096)
5978   {
5979     /*
5980       Enforce new long signal format,
5981       if this is not supported by the
5982       called node the request will fail
5983      */
5984     listTablesLongSignal = true;
5985   }
5986 
5987   /*
5988     Set table id and type according to old format
5989     in case sent to old nodes (during upgrade).
5990   */
5991   req->oldSetTableId(ltreq.getTableId());
5992   req->oldSetTableType(ltreq.getTableType());
5993 
5994   tSignal.theReceiversBlockNumber = DBDICT;
5995   tSignal.theVerId_signalNumber = GSN_LIST_TABLES_REQ;
5996   tSignal.theLength = ListTablesReq::SignalLength;
5997   if (listObjects(&tSignal, listTablesLongSignal) != 0)
5998     return -1;
5999 
6000   if (listTablesLongSignal)
6001   {
6002     return unpackListTables(list, fullyQualifiedNames);
6003   }
6004   else
6005   {
6006     return unpackOldListTables(list, fullyQualifiedNames);
6007   }
6008 }
6009 
6010 int
unpackListTables(NdbDictionary::Dictionary::List & list,bool fullyQualifiedNames)6011 NdbDictInterface::unpackListTables(NdbDictionary::Dictionary::List& list,
6012                                    bool fullyQualifiedNames)
6013 {
6014   Uint32 count = 0;
6015   Uint32* tableData = (Uint32*)m_tableData.get_data();
6016   Uint32* tableNames = (Uint32*)m_tableNames.get_data();
6017   const Uint32 listTablesDataSizeInWords = (sizeof(ListTablesData) + 3) / 4;
6018   list.count = m_noOfTables;
6019   list.elements = new NdbDictionary::Dictionary::List::Element[m_noOfTables];
6020 
6021   while (count < m_noOfTables)
6022   {
6023     NdbDictionary::Dictionary::List::Element& element = list.elements[count];
6024     ListTablesData _ltd;
6025     ListTablesData * ltd = &_ltd;
6026     memcpy(ltd, tableData, 4 * listTablesDataSizeInWords);
6027     tableData += listTablesDataSizeInWords;
6028     element.id = ltd->getTableId();
6029     element.type = (NdbDictionary::Object::Type)
6030       getApiConstant(ltd->getTableType(), objectTypeMapping, 0);
6031     element.state = (NdbDictionary::Object::State)
6032       getApiConstant(ltd->getTableState(), objectStateMapping, 0);
6033     element.store = (NdbDictionary::Object::Store)
6034       getApiConstant(ltd->getTableStore(), objectStoreMapping, 0);
6035     element.temp = ltd->getTableTemp();
6036     // table or index name
6037     BaseString databaseName;
6038     BaseString schemaName;
6039     BaseString objectName;
6040     if (!databaseName || !schemaName || !objectName)
6041     {
6042       m_error.code= 4000;
6043       return -1;
6044     }
6045     Uint32 size = tableNames[0];
6046     Uint32 wsize = (size + 3) / 4;
6047     tableNames++;
6048     if ((element.type == NdbDictionary::Object::UniqueHashIndex) ||
6049 	(element.type == NdbDictionary::Object::OrderedIndex)) {
6050       char * indexName = new char[size];
6051       if (indexName == NULL)
6052       {
6053         m_error.code= 4000;
6054         return -1;
6055       }
6056       memcpy(indexName, (char *) tableNames, size);
6057       if (!(databaseName = Ndb::getDatabaseFromInternalName(indexName)) ||
6058           !(schemaName = Ndb::getSchemaFromInternalName(indexName)))
6059       {
6060         delete [] indexName;
6061         m_error.code= 4000;
6062         return -1;
6063       }
6064       objectName = BaseString(Ndb::externalizeIndexName(indexName,
6065                                                         fullyQualifiedNames));
6066       delete [] indexName;
6067     } else if ((element.type == NdbDictionary::Object::SystemTable) ||
6068 	       (element.type == NdbDictionary::Object::UserTable)) {
6069       char * tableName = new char[size];
6070       if (tableName == NULL)
6071       {
6072         m_error.code= 4000;
6073         return -1;
6074       }
6075       memcpy(tableName, (char *) tableNames, size);
6076       if (!(databaseName = Ndb::getDatabaseFromInternalName(tableName)) ||
6077           !(schemaName = Ndb::getSchemaFromInternalName(tableName)))
6078       {
6079         delete [] tableName;
6080         m_error.code= 4000;
6081         return -1;
6082       }
6083       objectName = BaseString(Ndb::externalizeTableName(tableName,
6084                                                         fullyQualifiedNames));
6085       delete [] tableName;
6086     }
6087     else {
6088       char * otherName = new char[size];
6089       if (otherName == NULL)
6090       {
6091         m_error.code= 4000;
6092         return -1;
6093       }
6094       memcpy(otherName, (char *) tableNames, size);
6095       if (!(objectName = BaseString(otherName)))
6096       {
6097         m_error.code= 4000;
6098         return -1;
6099       }
6100       delete [] otherName;
6101     }
6102     if (!(element.database = new char[databaseName.length() + 1]) ||
6103         !(element.schema = new char[schemaName.length() + 1]) ||
6104         !(element.name = new char[objectName.length() + 1]))
6105     {
6106       m_error.code= 4000;
6107       return -1;
6108     }
6109     strcpy(element.database, databaseName.c_str());
6110     strcpy(element.schema, schemaName.c_str());
6111     strcpy(element.name, objectName.c_str());
6112     count++;
6113     tableNames += wsize;
6114   }
6115 
6116   return 0;
6117 }
6118 
6119 int
unpackOldListTables(NdbDictionary::Dictionary::List & list,bool fullyQualifiedNames)6120 NdbDictInterface::unpackOldListTables(NdbDictionary::Dictionary::List& list,
6121                                       bool fullyQualifiedNames)
6122 {
6123   // count
6124   const Uint32* data = (const Uint32*)m_buffer.get_data();
6125   const unsigned length = m_buffer.length() / 4;
6126   list.count = 0;
6127   bool ok = true;
6128   unsigned pos, count;
6129   pos = count = 0;
6130   while (pos < length) {
6131     // table id - name length - name
6132     pos++;
6133     if (pos >= length) {
6134       ok = false;
6135       break;
6136     }
6137     Uint32 n = (data[pos++] + 3) >> 2;
6138     pos += n;
6139     if (pos > length) {
6140       ok = false;
6141       break;
6142     }
6143     count++;
6144   }
6145   if (! ok) {
6146     // bad signal data
6147     m_error.code= 4213;
6148     return -1;
6149   }
6150   list.count = count;
6151   list.elements = new NdbDictionary::Dictionary::List::Element[count];
6152   pos = count = 0;
6153   while (pos < length) {
6154     NdbDictionary::Dictionary::List::Element& element = list.elements[count];
6155     Uint32 d = data[pos++];
6156     element.id = OldListTablesConf::getTableId(d);
6157     element.type = (NdbDictionary::Object::Type)
6158       getApiConstant(OldListTablesConf::getTableType(d), objectTypeMapping, 0);
6159     element.state = (NdbDictionary::Object::State)
6160       getApiConstant(OldListTablesConf::getTableState(d), objectStateMapping, 0);
6161     element.store = (NdbDictionary::Object::Store)
6162       getApiConstant(OldListTablesConf::getTableStore(d), objectStoreMapping, 0);
6163     element.temp = OldListTablesConf::getTableTemp(d);
6164     // table or index name
6165     Uint32 n = (data[pos++] + 3) >> 2;
6166     BaseString databaseName;
6167     BaseString schemaName;
6168     BaseString objectName;
6169     if (!databaseName || !schemaName || !objectName)
6170     {
6171       m_error.code= 4000;
6172       return -1;
6173     }
6174     if ((element.type == NdbDictionary::Object::UniqueHashIndex) ||
6175 	(element.type == NdbDictionary::Object::OrderedIndex)) {
6176       char * indexName = new char[n << 2];
6177       if (indexName == NULL)
6178       {
6179         m_error.code= 4000;
6180         return -1;
6181       }
6182       memcpy(indexName, &data[pos], n << 2);
6183       if (!(databaseName = Ndb::getDatabaseFromInternalName(indexName)) ||
6184           !(schemaName = Ndb::getSchemaFromInternalName(indexName)))
6185       {
6186         delete [] indexName;
6187         m_error.code= 4000;
6188         return -1;
6189       }
6190       objectName = BaseString(Ndb::externalizeIndexName(indexName, fullyQualifiedNames));
6191       delete [] indexName;
6192     } else if ((element.type == NdbDictionary::Object::SystemTable) ||
6193 	       (element.type == NdbDictionary::Object::UserTable)) {
6194       char * tableName = new char[n << 2];
6195       if (tableName == NULL)
6196       {
6197         m_error.code= 4000;
6198         return -1;
6199       }
6200       memcpy(tableName, &data[pos], n << 2);
6201       if (!(databaseName = Ndb::getDatabaseFromInternalName(tableName)) ||
6202           !(schemaName = Ndb::getSchemaFromInternalName(tableName)))
6203       {
6204         delete [] tableName;
6205         m_error.code= 4000;
6206         return -1;
6207       }
6208       objectName = BaseString(Ndb::externalizeTableName(tableName, fullyQualifiedNames));
6209       delete [] tableName;
6210     }
6211     else {
6212       char * otherName = new char[n << 2];
6213       if (otherName == NULL)
6214       {
6215         m_error.code= 4000;
6216         return -1;
6217       }
6218       memcpy(otherName, &data[pos], n << 2);
6219       if (!(objectName = BaseString(otherName)))
6220       {
6221         m_error.code= 4000;
6222         return -1;
6223       }
6224       delete [] otherName;
6225     }
6226     if (!(element.database = new char[databaseName.length() + 1]) ||
6227         !(element.schema = new char[schemaName.length() + 1]) ||
6228         !(element.name = new char[objectName.length() + 1]))
6229     {
6230       m_error.code= 4000;
6231       return -1;
6232     }
6233     strcpy(element.database, databaseName.c_str());
6234     strcpy(element.schema, schemaName.c_str());
6235     strcpy(element.name, objectName.c_str());
6236     pos += n;
6237     count++;
6238   }
6239   return 0;
6240 }
6241 
6242 int
listObjects(NdbApiSignal * signal,bool & listTablesLongSignal)6243 NdbDictInterface::listObjects(NdbApiSignal* signal,
6244                               bool& listTablesLongSignal)
6245 {
6246   const Uint32 RETRIES = 100;
6247   for (Uint32 i = 0; i < RETRIES; i++) {
6248     m_buffer.clear();
6249     // begin protected
6250     /*
6251       The PollGuard has an implicit call of unlock_and_signal through the
6252       ~PollGuard method. This method is called implicitly by the compiler
6253       in all places where the object is out of context due to a return,
6254       break, continue or simply end of statement block
6255     */
6256     PollGuard poll_guard(* m_impl);
6257     Uint16 aNodeId = getTransporter()->get_an_alive_node();
6258     if (aNodeId == 0) {
6259       if (getTransporter()->is_cluster_completely_unavailable())
6260       {
6261         m_error.code= 4009;
6262       }
6263       else
6264       {
6265         m_error.code = 4035;
6266       }
6267       return -1;
6268     }
6269     NodeInfo info = m_impl->getNodeInfo(aNodeId).m_info;
6270     if (ndbd_LIST_TABLES_CONF_long_signal(info.m_version))
6271     {
6272       /*
6273         Called node will return a long signal
6274        */
6275       listTablesLongSignal = true;
6276     }
6277     else if (listTablesLongSignal)
6278     {
6279       /*
6280         We are requesting info from a table with table id > 4096
6281         and older versions don't support that, bug#36044
6282       */
6283       m_error.code= 4105;
6284       return -1;
6285     }
6286 
6287     if (m_impl->sendSignal(signal, aNodeId) != 0) {
6288       continue;
6289     }
6290     m_impl->incClientStat(Ndb::WaitMetaRequestCount, 1);
6291     m_error.code= 0;
6292     int ret_val= poll_guard.wait_n_unlock(DICT_WAITFOR_TIMEOUT,
6293                                           aNodeId, WAIT_LIST_TABLES_CONF,
6294                                           true);
6295     // end protected
6296     if (ret_val == 0 && m_error.code == 0)
6297       return 0;
6298     if (ret_val == -2) //WAIT_NODE_FAILURE
6299       continue;
6300     return -1;
6301   }
6302   return -1;
6303 }
6304 
6305 void
execLIST_TABLES_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])6306 NdbDictInterface::execLIST_TABLES_CONF(const NdbApiSignal* signal,
6307                                        const LinearSectionPtr ptr[3])
6308 {
6309   Uint16 nodeId = refToNode(signal->theSendersBlockRef);
6310   NodeInfo info = m_impl->getNodeInfo(nodeId).m_info;
6311   if (!ndbd_LIST_TABLES_CONF_long_signal(info.m_version))
6312   {
6313     /*
6314       Sender doesn't support new signal format
6315      */
6316     NdbDictInterface::execOLD_LIST_TABLES_CONF(signal, ptr);
6317     return;
6318   }
6319 
6320   if (signal->isFirstFragment())
6321   {
6322     m_fragmentId = signal->getFragmentId();
6323     m_noOfTables = 0;
6324     m_tableData.clear();
6325     m_tableNames.clear();
6326   }
6327   else
6328   {
6329     if (m_fragmentId != signal->getFragmentId())
6330     {
6331       abort();
6332     }
6333   }
6334 
6335   /*
6336     Save the count
6337    */
6338   const ListTablesConf* const conf=
6339     CAST_CONSTPTR(ListTablesConf, signal->getDataPtr());
6340   m_noOfTables+= conf->noOfTables;
6341 
6342   bool fragmented = signal->isFragmented();
6343   Uint32 sigLen = signal->getLength() - 1;
6344   const Uint32 secs = signal->m_noOfSections;
6345   const Uint32 directMap[3] = {0,1,2};
6346   const Uint32 * const secNos =
6347     (fragmented) ?
6348     &signal->getDataPtr()[sigLen - secs]
6349     : (const Uint32 *) &directMap;
6350 
6351   for(Uint32 i = 0; i<secs; i++)
6352   {
6353     Uint32 sectionNo = secNos[i];
6354     switch (sectionNo) {
6355     case(ListTablesConf::TABLE_DATA):
6356       if (m_tableData.append(ptr[i].p, 4 * ptr[i].sz))
6357       {
6358         m_error.code= 4000;
6359         goto end;
6360       }
6361       break;
6362     case(ListTablesConf::TABLE_NAMES):
6363       if (m_tableNames.append(ptr[i].p, 4 * ptr[i].sz))
6364       {
6365         m_error.code= 4000;
6366         goto end;
6367       }
6368       break;
6369     default:
6370       abort();
6371     }
6372   }
6373 
6374  end:
6375   if(!signal->isLastFragment()){
6376     return;
6377   }
6378 
6379   m_impl->theWaiter.signal(NO_WAIT);
6380 }
6381 
6382 
6383 void
execOLD_LIST_TABLES_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])6384 NdbDictInterface::execOLD_LIST_TABLES_CONF(const NdbApiSignal* signal,
6385                                            const LinearSectionPtr ptr[3])
6386 {
6387   const unsigned off = OldListTablesConf::HeaderLength;
6388   const unsigned len = (signal->getLength() - off);
6389   if (m_buffer.append(signal->getDataPtr() + off, len << 2))
6390   {
6391     m_error.code= 4000;
6392   }
6393   if (signal->getLength() < OldListTablesConf::SignalLength) {
6394     // last signal has less than full length
6395     m_impl->theWaiter.signal(NO_WAIT);
6396   }
6397 }
6398 
6399 int
forceGCPWait(int type)6400 NdbDictionaryImpl::forceGCPWait(int type)
6401 {
6402   return m_receiver.forceGCPWait(type);
6403 }
6404 
6405 int
forceGCPWait(int type)6406 NdbDictInterface::forceGCPWait(int type)
6407 {
6408   NdbApiSignal tSignal(m_reference);
6409   if (type == 0 || type == 2)
6410   {
6411     WaitGCPReq* const req = CAST_PTR(WaitGCPReq, tSignal.getDataPtrSend());
6412     req->senderRef = m_reference;
6413     req->senderData = 0;
6414     req->requestType =
6415       type == 0 ?
6416       WaitGCPReq::CompleteForceStart : WaitGCPReq::RestartGCI;
6417 
6418     tSignal.theReceiversBlockNumber = DBDIH;
6419     tSignal.theVerId_signalNumber = GSN_WAIT_GCP_REQ;
6420     tSignal.theLength = WaitGCPReq::SignalLength;
6421 
6422     const Uint32 RETRIES = 100;
6423     for (Uint32 i = 0; i < RETRIES; i++)
6424     {
6425       PollGuard pg(* m_impl);
6426       Uint16 aNodeId = getTransporter()->get_an_alive_node();
6427       if (aNodeId == 0) {
6428         if (getTransporter()->is_cluster_completely_unavailable())
6429         {
6430           m_error.code= 4009;
6431         }
6432         else
6433         {
6434           m_error.code = 4035;
6435         }
6436         return -1;
6437       }
6438       if (m_impl->sendSignal(&tSignal, aNodeId) != 0)
6439       {
6440         continue;
6441       }
6442 
6443       m_error.code= 0;
6444 
6445       m_impl->incClientStat(Ndb::WaitMetaRequestCount, 1);
6446       int ret_val= pg.wait_n_unlock(DICT_WAITFOR_TIMEOUT,
6447                                     aNodeId, WAIT_LIST_TABLES_CONF);
6448       // end protected
6449       if (ret_val == 0 && m_error.code == 0)
6450         return 0;
6451       if (ret_val == -2) //WAIT_NODE_FAILURE
6452         continue;
6453       return -1;
6454     }
6455     return -1;
6456   }
6457   else if (type == 1)
6458   {
6459     tSignal.getDataPtrSend()[0] = 6099;
6460     tSignal.theReceiversBlockNumber = DBDIH;
6461     tSignal.theVerId_signalNumber = GSN_DUMP_STATE_ORD;
6462     tSignal.theLength = 1;
6463 
6464     const Uint32 RETRIES = 100;
6465     for (Uint32 i = 0; i < RETRIES; i++)
6466     {
6467       m_impl->lock();
6468       Uint16 aNodeId = getTransporter()->get_an_alive_node();
6469       if (aNodeId == 0) {
6470         if (getTransporter()->is_cluster_completely_unavailable())
6471         {
6472           m_error.code= 4009;
6473         }
6474         else
6475         {
6476           m_error.code = 4035;
6477         }
6478         m_impl->unlock();
6479         return -1;
6480       }
6481       if (m_impl->sendSignal(&tSignal, aNodeId) != 0) {
6482         m_impl->unlock();
6483         continue;
6484       }
6485 
6486       m_impl->do_forceSend();
6487       m_impl->unlock();
6488     }
6489     return m_error.code == 0 ? 0 : -1;
6490   }
6491   else
6492   {
6493     m_error.code = 4003;
6494   }
6495   return -1;
6496 }
6497 
6498 int
getRestartGCI(Uint32 * gci)6499 NdbDictionaryImpl::getRestartGCI(Uint32 * gci)
6500 {
6501   int res = m_receiver.forceGCPWait(2);
6502   if (res == 0 && gci != 0)
6503   {
6504     * gci = m_receiver.m_data.m_wait_gcp_conf.gci_hi;
6505   }
6506   return res;
6507 }
6508 
6509 void
execWAIT_GCP_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])6510 NdbDictInterface::execWAIT_GCP_CONF(const NdbApiSignal* signal,
6511 				    const LinearSectionPtr ptr[3])
6512 {
6513   const WaitGCPConf* conf = CAST_CONSTPTR(WaitGCPConf, signal->getDataPtr());
6514 
6515   m_data.m_wait_gcp_conf.gci_lo = conf->gci_lo;
6516   m_data.m_wait_gcp_conf.gci_hi = conf->gci_hi;
6517   m_impl->theWaiter.signal(NO_WAIT);
6518 }
6519 
6520 void
execWAIT_GCP_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])6521 NdbDictInterface::execWAIT_GCP_REF(const NdbApiSignal* signal,
6522                                    const LinearSectionPtr ptr[3])
6523 {
6524   DBUG_ENTER("NdbDictInterface::WAIT_GCP_REF");
6525   const WaitGCPRef* ref = CAST_CONSTPTR(WaitGCPRef, signal->getDataPtr());
6526   m_error.code = ref->errorCode;
6527   DBUG_PRINT("info", ("Error code = %d", m_error.code));
6528 
6529   m_impl->theWaiter.signal(NO_WAIT);
6530   DBUG_VOID_RETURN;
6531 }
6532 
NdbFilegroupImpl(NdbDictionary::Object::Type t)6533 NdbFilegroupImpl::NdbFilegroupImpl(NdbDictionary::Object::Type t)
6534   : NdbDictObjectImpl(t)
6535 {
6536   m_extent_size = 0;
6537   m_undo_buffer_size = 0;
6538   m_logfile_group_id = RNIL;
6539   m_logfile_group_version = ~0;
6540 }
6541 
NdbTablespaceImpl()6542 NdbTablespaceImpl::NdbTablespaceImpl() :
6543   NdbDictionary::Tablespace(* this),
6544   NdbFilegroupImpl(NdbDictionary::Object::Tablespace), m_facade(this)
6545 {
6546 }
6547 
NdbTablespaceImpl(NdbDictionary::Tablespace & f)6548 NdbTablespaceImpl::NdbTablespaceImpl(NdbDictionary::Tablespace & f) :
6549   NdbDictionary::Tablespace(* this),
6550   NdbFilegroupImpl(NdbDictionary::Object::Tablespace), m_facade(&f)
6551 {
6552 }
6553 
~NdbTablespaceImpl()6554 NdbTablespaceImpl::~NdbTablespaceImpl(){
6555 }
6556 
6557 int
assign(const NdbTablespaceImpl & org)6558 NdbTablespaceImpl::assign(const NdbTablespaceImpl& org)
6559 {
6560   m_id = org.m_id;
6561   m_version = org.m_version;
6562   m_status = org.m_status;
6563   m_type = org.m_type;
6564 
6565   if (!m_name.assign(org.m_name))
6566     return -1;
6567   m_grow_spec = org.m_grow_spec;
6568   m_extent_size = org.m_extent_size;
6569   m_undo_free_words = org.m_undo_free_words;
6570   m_logfile_group_id = org.m_logfile_group_id;
6571   m_logfile_group_version = org.m_logfile_group_version;
6572   if (!m_logfile_group_name.assign(org.m_logfile_group_name))
6573     return -1;
6574   m_undo_free_words = org.m_undo_free_words;
6575   return 0;
6576 }
6577 
NdbLogfileGroupImpl()6578 NdbLogfileGroupImpl::NdbLogfileGroupImpl() :
6579   NdbDictionary::LogfileGroup(* this),
6580   NdbFilegroupImpl(NdbDictionary::Object::LogfileGroup), m_facade(this)
6581 {
6582 }
6583 
NdbLogfileGroupImpl(NdbDictionary::LogfileGroup & f)6584 NdbLogfileGroupImpl::NdbLogfileGroupImpl(NdbDictionary::LogfileGroup & f) :
6585   NdbDictionary::LogfileGroup(* this),
6586   NdbFilegroupImpl(NdbDictionary::Object::LogfileGroup), m_facade(&f)
6587 {
6588 }
6589 
~NdbLogfileGroupImpl()6590 NdbLogfileGroupImpl::~NdbLogfileGroupImpl(){
6591 }
6592 
6593 int
assign(const NdbLogfileGroupImpl & org)6594 NdbLogfileGroupImpl::assign(const NdbLogfileGroupImpl& org)
6595 {
6596   m_id = org.m_id;
6597   m_version = org.m_version;
6598   m_status = org.m_status;
6599   m_type = org.m_type;
6600 
6601   if (!m_name.assign(org.m_name))
6602     return -1;
6603   m_grow_spec = org.m_grow_spec;
6604   m_extent_size = org.m_extent_size;
6605   m_undo_free_words = org.m_undo_free_words;
6606   m_logfile_group_id = org.m_logfile_group_id;
6607   m_logfile_group_version = org.m_logfile_group_version;
6608   if (!m_logfile_group_name.assign(org.m_logfile_group_name))
6609     return -1;
6610   m_undo_free_words = org.m_undo_free_words;
6611   return 0;
6612 }
6613 
NdbFileImpl(NdbDictionary::Object::Type t)6614 NdbFileImpl::NdbFileImpl(NdbDictionary::Object::Type t)
6615   : NdbDictObjectImpl(t)
6616 {
6617   m_size = 0;
6618   m_free = 0;
6619   m_filegroup_id = RNIL;
6620   m_filegroup_version = ~0;
6621 }
6622 
NdbDatafileImpl()6623 NdbDatafileImpl::NdbDatafileImpl() :
6624   NdbDictionary::Datafile(* this),
6625   NdbFileImpl(NdbDictionary::Object::Datafile), m_facade(this)
6626 {
6627 }
6628 
NdbDatafileImpl(NdbDictionary::Datafile & f)6629 NdbDatafileImpl::NdbDatafileImpl(NdbDictionary::Datafile & f) :
6630   NdbDictionary::Datafile(* this),
6631   NdbFileImpl(NdbDictionary::Object::Datafile), m_facade(&f)
6632 {
6633 }
6634 
~NdbDatafileImpl()6635 NdbDatafileImpl::~NdbDatafileImpl(){
6636 }
6637 
6638 int
assign(const NdbDatafileImpl & org)6639 NdbDatafileImpl::assign(const NdbDatafileImpl& org)
6640 {
6641   m_id = org.m_id;
6642   m_version = org.m_version;
6643   m_status = org.m_status;
6644   m_type = org.m_type;
6645 
6646   m_size = org.m_size;
6647   m_free = org.m_free;
6648   m_filegroup_id = org.m_filegroup_id;
6649   m_filegroup_version = org.m_filegroup_version;
6650   if (!m_path.assign(org.m_path) ||
6651       !m_filegroup_name.assign(org.m_filegroup_name))
6652     return -1;
6653   return 0;
6654 }
6655 
NdbUndofileImpl()6656 NdbUndofileImpl::NdbUndofileImpl() :
6657   NdbDictionary::Undofile(* this),
6658   NdbFileImpl(NdbDictionary::Object::Undofile), m_facade(this)
6659 {
6660 }
6661 
NdbUndofileImpl(NdbDictionary::Undofile & f)6662 NdbUndofileImpl::NdbUndofileImpl(NdbDictionary::Undofile & f) :
6663   NdbDictionary::Undofile(* this),
6664   NdbFileImpl(NdbDictionary::Object::Undofile), m_facade(&f)
6665 {
6666 }
6667 
~NdbUndofileImpl()6668 NdbUndofileImpl::~NdbUndofileImpl(){
6669 }
6670 
6671 int
assign(const NdbUndofileImpl & org)6672 NdbUndofileImpl::assign(const NdbUndofileImpl& org)
6673 {
6674   m_id = org.m_id;
6675   m_version = org.m_version;
6676   m_status = org.m_status;
6677   m_type = org.m_type;
6678 
6679   m_size = org.m_size;
6680   m_free = org.m_free;
6681   m_filegroup_id = org.m_filegroup_id;
6682   m_filegroup_version = org.m_filegroup_version;
6683   if (!m_path.assign(org.m_path) ||
6684       !m_filegroup_name.assign(org.m_filegroup_name))
6685     return 4000;
6686   return 0;
6687 }
6688 
6689 int
createDatafile(const NdbDatafileImpl & file,bool force,NdbDictObjectImpl * obj)6690 NdbDictionaryImpl::createDatafile(const NdbDatafileImpl & file,
6691 				  bool force,
6692 				  NdbDictObjectImpl* obj)
6693 
6694 {
6695   DBUG_ENTER("NdbDictionaryImpl::createDatafile");
6696   NdbFilegroupImpl tmp(NdbDictionary::Object::Tablespace);
6697   if(file.m_filegroup_version != ~(Uint32)0){
6698     tmp.m_id = file.m_filegroup_id;
6699     tmp.m_version = file.m_filegroup_version;
6700     DBUG_RETURN(m_receiver.create_file(file, tmp, force, obj));
6701   }
6702 
6703 
6704   if(m_receiver.get_filegroup(tmp, NdbDictionary::Object::Tablespace,
6705 			      file.m_filegroup_name.c_str()) == 0){
6706     DBUG_RETURN(m_receiver.create_file(file, tmp, force, obj));
6707   }
6708   DBUG_RETURN(-1);
6709 }
6710 
6711 int
dropDatafile(const NdbDatafileImpl & file)6712 NdbDictionaryImpl::dropDatafile(const NdbDatafileImpl & file){
6713   return m_receiver.drop_file(file);
6714 }
6715 
6716 int
createUndofile(const NdbUndofileImpl & file,bool force,NdbDictObjectImpl * obj)6717 NdbDictionaryImpl::createUndofile(const NdbUndofileImpl & file,
6718 				  bool force,
6719 				  NdbDictObjectImpl* obj)
6720 {
6721   DBUG_ENTER("NdbDictionaryImpl::createUndofile");
6722   NdbFilegroupImpl tmp(NdbDictionary::Object::LogfileGroup);
6723   if(file.m_filegroup_version != ~(Uint32)0){
6724     tmp.m_id = file.m_filegroup_id;
6725     tmp.m_version = file.m_filegroup_version;
6726     DBUG_RETURN(m_receiver.create_file(file, tmp, force, obj));
6727   }
6728 
6729 
6730   if(m_receiver.get_filegroup(tmp, NdbDictionary::Object::LogfileGroup,
6731 			      file.m_filegroup_name.c_str()) == 0){
6732     DBUG_RETURN(m_receiver.create_file(file, tmp, force, obj));
6733   }
6734   DBUG_PRINT("info", ("Failed to find filegroup"));
6735   m_error.code = 789;
6736   DBUG_RETURN(-1);
6737 }
6738 
6739 int
dropUndofile(const NdbUndofileImpl & file)6740 NdbDictionaryImpl::dropUndofile(const NdbUndofileImpl & file)
6741 {
6742   return m_receiver.drop_file(file);
6743 }
6744 
6745 int
createTablespace(const NdbTablespaceImpl & fg,NdbDictObjectImpl * obj)6746 NdbDictionaryImpl::createTablespace(const NdbTablespaceImpl & fg,
6747 				    NdbDictObjectImpl* obj)
6748 {
6749   return m_receiver.create_filegroup(fg, obj);
6750 }
6751 
6752 int
dropTablespace(const NdbTablespaceImpl & fg)6753 NdbDictionaryImpl::dropTablespace(const NdbTablespaceImpl & fg)
6754 {
6755   return m_receiver.drop_filegroup(fg);
6756 }
6757 
6758 int
createLogfileGroup(const NdbLogfileGroupImpl & fg,NdbDictObjectImpl * obj)6759 NdbDictionaryImpl::createLogfileGroup(const NdbLogfileGroupImpl & fg,
6760 				      NdbDictObjectImpl* obj)
6761 {
6762   return m_receiver.create_filegroup(fg, obj);
6763 }
6764 
6765 int
dropLogfileGroup(const NdbLogfileGroupImpl & fg)6766 NdbDictionaryImpl::dropLogfileGroup(const NdbLogfileGroupImpl & fg)
6767 {
6768   return m_receiver.drop_filegroup(fg);
6769 }
6770 
6771 static int
cmp_ndbrec_attr(const void * a,const void * b)6772 cmp_ndbrec_attr(const void *a, const void *b)
6773 {
6774   const NdbRecord::Attr *r1= (const NdbRecord::Attr *)a;
6775   const NdbRecord::Attr *r2= (const NdbRecord::Attr *)b;
6776   if(r1->attrId < r2->attrId)
6777     return -1;
6778   else if(r1->attrId == r2->attrId)
6779     return 0;
6780   else
6781     return 1;
6782 }
6783 
6784 struct BitRange{
6785   Uint64 start; /* First occupied bit */
6786   Uint64 end; /* Last occupied bit */
6787 };
6788 
6789 static int
cmp_bitrange(const void * a,const void * b)6790 cmp_bitrange(const void* a, const void* b)
6791 {
6792   /* Sort them by start bit */
6793   const BitRange& brA= *(const BitRange*)a;
6794   const BitRange& brB= *(const BitRange*)b;
6795 
6796   if (brA.start < brB.start)
6797     return -1;
6798   else if (brA.start == brB.start)
6799     return 0;
6800   else
6801     return 1;
6802 }
6803 
6804 bool
validateRecordSpec(const NdbDictionary::RecordSpecification * recSpec,Uint32 length,Uint32 flags)6805 NdbDictionaryImpl::validateRecordSpec(const NdbDictionary::RecordSpecification *recSpec,
6806                                       Uint32 length,
6807                                       Uint32 flags)
6808 {
6809   /* We check that there's no overlap between any of the data values
6810    * or Null bits
6811    */
6812 
6813   /* Column data + NULL bits with at least 1 non nullable PK */
6814   const Uint32 MaxRecordElements= (2* NDB_MAX_ATTRIBUTES_IN_TABLE) - 1;
6815   Uint32 numElements= 0;
6816   BitRange bitRanges[ MaxRecordElements ];
6817 
6818   if (length > NDB_MAX_ATTRIBUTES_IN_TABLE)
6819   {
6820     m_error.code= 4548;
6821     return false;
6822   }
6823 
6824   /* Populate bitRanges array with ranges of bits occupied by
6825    * data values and null bits
6826    */
6827   for (Uint32 rs=0; rs < length; rs++)
6828   {
6829     const NdbDictionary::Column* col= recSpec[rs].column;
6830     Uint64 elementByteOffset= recSpec[rs].offset;
6831     Uint64 elementByteLength= col->getSizeInBytesForRecord();
6832     Uint64 nullLength= col->getNullable() ? 1 : 0;
6833 
6834     /*
6835      Validate column flags
6836      1. Check if the column_flag has any invalid values
6837      2. If the BitColMapsNullBitOnly flag is enabled, RecMysqldBitfield
6838         should have been enabled and the column length should be 1
6839     */
6840     if((flags & NdbDictionary::RecPerColumnFlags) &&
6841        (recSpec[rs].column_flags &
6842            ~NdbDictionary::RecordSpecification::BitColMapsNullBitOnly) &&
6843        ((recSpec[rs].column_flags &
6844             NdbDictionary::RecordSpecification::BitColMapsNullBitOnly) &&
6845          !((col->getLength() == 1) &&
6846            (flags & NdbDictionary::RecMysqldBitfield))))
6847     {
6848       m_error.code= 4556;
6849       return false;
6850     }
6851 
6852     const NdbDictionary::Column::Type type= col->getType();
6853     if ((type == NdbDictionary::Column::Bit) &&
6854         (flags & NdbDictionary::RecMysqldBitfield))
6855     {
6856       if((flags & NdbDictionary::RecPerColumnFlags) &&
6857          (recSpec[rs].column_flags &
6858             NdbDictionary::RecordSpecification::BitColMapsNullBitOnly))
6859       {
6860         /* skip counting overflow bits */
6861         elementByteLength = 0;
6862       }
6863       else
6864       {
6865         /* MySQLD Bit format puts 'fractional' part of bit types
6866          * in with the null bits - so there's 1 optional Null
6867          * bit followed by n (max 7) databits, at position
6868          * given by the nullbit offsets.  Then the rest of
6869          * the bytes go at the normal offset position.
6870          */
6871         Uint32 bitLength= col->getLength();
6872         Uint32 fractionalBits= bitLength % 8;
6873         nullLength+= fractionalBits;
6874         elementByteLength= bitLength / 8;
6875       }
6876     }
6877 
6878     /* Does the element itself have any bytes?
6879      * (MySQLD bit format may have all data as 'null bits'
6880      */
6881     if (elementByteLength)
6882     {
6883       bitRanges[numElements].start= 8 * elementByteOffset;
6884       bitRanges[numElements].end= (8 * (elementByteOffset + elementByteLength)) - 1;
6885 
6886       numElements++;
6887     }
6888 
6889     if (nullLength)
6890     {
6891       bitRanges[numElements].start=
6892         (8* recSpec[rs].nullbit_byte_offset) +
6893         recSpec[rs].nullbit_bit_in_byte;
6894       bitRanges[numElements].end= bitRanges[numElements].start +
6895         (nullLength -1);
6896 
6897       numElements++;
6898     }
6899   }
6900 
6901   /* Now sort the 'elements' by start bit */
6902   qsort(bitRanges,
6903         numElements,
6904         sizeof(BitRange),
6905         cmp_bitrange);
6906 
6907   Uint64 endOfPreviousRange= bitRanges[0].end;
6908 
6909   /* Now check that there's no overlaps */
6910   for (Uint32 rangeNum= 1; rangeNum < numElements; rangeNum++)
6911   {
6912     if (unlikely((bitRanges[rangeNum].start <= endOfPreviousRange)))
6913     {
6914       /* Oops, this range overlaps with previous one */
6915       m_error.code= 4547;
6916       return false;
6917     }
6918     endOfPreviousRange= bitRanges[rangeNum].end;
6919   }
6920 
6921   /* All relevant ranges are distinct */
6922   return true;
6923 }
6924 
6925 
6926 /* ndb_set_record_specification
6927  * This procedure sets the contents of the passed RecordSpecification
6928  * for the given column in the given table.
6929  * The column is placed at the storageOffset given, and a new
6930  * storageOffset, beyond the end of this column, is returned.
6931  * Null bits are stored at the start of the row in consecutive positions.
6932  * The caller must ensure that enough space exists for all of the nullable
6933  * columns, before the first bit of data.
6934  * The new storageOffset is returned.
6935  */
6936 static Uint32
ndb_set_record_specification(Uint32 storageOffset,Uint32 field_num,Uint32 & nullableColNum,NdbDictionary::RecordSpecification * spec,NdbColumnImpl * col)6937 ndb_set_record_specification(Uint32 storageOffset,
6938                              Uint32 field_num,
6939                              Uint32& nullableColNum,
6940                              NdbDictionary::RecordSpecification *spec,
6941                              NdbColumnImpl *col)
6942 {
6943   spec->column= col->m_facade;
6944 
6945   spec->offset= storageOffset;
6946   /* For Blobs we just need the NdbBlob* */
6947   const Uint32 sizeOfElement= col->getBlobType() ?
6948     sizeof(NdbBlob*) :
6949     spec->column->getSizeInBytes();
6950 
6951   if (spec->column->getNullable())
6952   {
6953     spec->nullbit_byte_offset= (nullableColNum >> 3);
6954     spec->nullbit_bit_in_byte= (nullableColNum & 7);
6955     nullableColNum ++;
6956   }
6957   else
6958   {
6959     /* For non-nullable columns, use visibly bad offsets */
6960     spec->nullbit_byte_offset= ~0;
6961     spec->nullbit_bit_in_byte= ~0;
6962   }
6963 
6964   return storageOffset + sizeOfElement;
6965 }
6966 
6967 
6968 /* This method creates an NdbRecord for the given table or index which
6969  * contains all columns (except pseudo columns).
6970  * For a table, only the tableOrIndex parameter should be supplied.
6971  * For an index, the index 'table object' should be supplied as the
6972  * tableOrIndex parameter, and the underlying indexed table object
6973  * should be supplied as the baseTableForIndex parameter.
6974  * The underlying table object is required to get the correct column
6975  * objects to build the NdbRecord object.
6976  * The record is created with all null bits packed together starting
6977  * from the first word, in attrId order, followed by all attributes
6978  * in attribute order.
6979  */
6980 int
createDefaultNdbRecord(NdbTableImpl * tableOrIndex,const NdbTableImpl * baseTableForIndex)6981 NdbDictionaryImpl::createDefaultNdbRecord(NdbTableImpl *tableOrIndex,
6982                                           const NdbTableImpl *baseTableForIndex)
6983 {
6984   /* We create a full NdbRecord for the columns in the table
6985    */
6986   DBUG_ENTER("NdbDictionaryImpl::createNdbRecords()");
6987   NdbDictionary::RecordSpecification spec[NDB_MAX_ATTRIBUTES_IN_TABLE];
6988   NdbRecord *rec;
6989   Uint32 i;
6990   Uint32 numCols= tableOrIndex->m_columns.size();
6991   // Reserve space for Null bits at the start
6992   Uint32 baseTabCols= numCols;
6993   unsigned char* pkMask= NULL;
6994   bool isIndex= false;
6995 
6996   if (baseTableForIndex != NULL)
6997   {
6998     /* Check we've really got an index */
6999     assert((tableOrIndex->m_indexType == NdbDictionary::Object::OrderedIndex ||
7000             tableOrIndex->m_indexType == NdbDictionary::Object::UniqueHashIndex));
7001 
7002     /* Update baseTabCols to real number of cols in indexed table */
7003     baseTabCols= baseTableForIndex->m_columns.size();
7004 
7005     /* Ignore extra info column at end of index table */
7006     numCols--;
7007 
7008     isIndex= true;
7009 
7010     // Could do further string checks to make sure the base table and
7011     // index are related
7012   }
7013   else
7014   {
7015     /* Check we've not got an index */
7016     assert((tableOrIndex->m_indexType != NdbDictionary::Object::OrderedIndex &&
7017             tableOrIndex->m_indexType != NdbDictionary::Object::UniqueHashIndex));
7018   }
7019 
7020   Uint32 nullableCols= 0;
7021   /* Determine number of nullable columns */
7022   for (i=0; i<numCols; i++)
7023   {
7024     /* As the Index NdbRecord is built using Columns from the base table,
7025      * it will get/set Null according to their Nullability.
7026      * If this is an index, then we need to take the 'Nullability' from
7027      * the base table column objects - unique index table column objects
7028      * will not be nullable as they are part of the key.
7029      */
7030     const NdbColumnImpl* col= NULL;
7031 
7032     if (isIndex)
7033     {
7034       Uint32 baseTableColNum=
7035         tableOrIndex->m_index->m_columns[i]->m_keyInfoPos;
7036       col= baseTableForIndex->m_columns[baseTableColNum];
7037     }
7038     else
7039     {
7040       col= tableOrIndex->m_columns[i];
7041     }
7042 
7043     if (col->m_nullable)
7044       nullableCols ++;
7045   }
7046 
7047   /* Offset of first byte of data in the NdbRecord */
7048   Uint32 offset= (nullableCols+7) / 8;
7049 
7050   /* Allocate and zero column presence bitmasks */
7051   Uint32 bitMaskBytes= (baseTabCols + 7) / 8;
7052   pkMask=    (unsigned char*) calloc(1, bitMaskBytes);
7053 
7054   if (pkMask == NULL)
7055   {
7056     /* Memory allocation problem */
7057     m_error.code= 4000;
7058     return -1;
7059   }
7060 
7061   Uint32 nullableColNum= 0;
7062 
7063   /* Build record specification array for this table. */
7064   for (i= 0; i < numCols; i++)
7065   {
7066     /* Have to use columns from 'real' table for indexes as described
7067      * in NdbRecord documentation
7068      */
7069     NdbColumnImpl *col= NULL;
7070 
7071     if (isIndex)
7072     {
7073       /* From index table, get m_index pointer to NdbIndexImpl object.
7074        * m_index has m_key_ids[] array mapping index column numbers to
7075        * real table column numbers.
7076        * Use this number to get the correct column object from the
7077        * base table structure
7078        * No need to worry about Blobs here as Blob columns can't be
7079        * indexed
7080        */
7081       Uint32 baseTableColNum=
7082         tableOrIndex->m_index->m_columns[i]->m_keyInfoPos;
7083       col= baseTableForIndex->m_columns[baseTableColNum];
7084 
7085       /* Set pk bitmask bit based on the base-table col number of this
7086        * column
7087        */
7088       assert( baseTableColNum < baseTabCols);
7089       pkMask[ baseTableColNum >> 3 ] |= ( 1 << ( baseTableColNum & 7 ));
7090     }
7091     else
7092     {
7093       col= tableOrIndex->m_columns[i];
7094 
7095       if (col->m_pk)
7096       {
7097         /* Set pk bitmask bit based on the col number of this column */
7098         pkMask[ i >> 3 ] |= ( 1 << (i & 7));
7099       }
7100 
7101       /* If this column's a Blob then we need to create
7102        * a default NdbRecord for the Blob table too
7103        * (unless it's a really small one with no parts table).
7104        */
7105       if (col->getBlobType() && col->getPartSize() != 0)
7106       {
7107         if (likely(col->m_blobTable != NULL))
7108         {
7109           int res= createDefaultNdbRecord(col->m_blobTable, NULL);
7110           if (res != 0)
7111           {
7112             free(pkMask);
7113             DBUG_RETURN(-1);
7114           }
7115         }
7116         else
7117         {
7118           if (!ignore_broken_blob_tables())
7119           {
7120             assert(false);
7121             /* 4263 - Invalid blob attributes or invalid blob parts table */
7122             m_error.code = 4263;
7123             free(pkMask);
7124             DBUG_RETURN(-1);
7125           }
7126         }
7127       }
7128     }
7129 
7130     offset= ndb_set_record_specification(offset,
7131                                          i,
7132                                          nullableColNum,
7133                                          &spec[i],
7134                                          col);
7135   }
7136 
7137   rec= createRecord(tableOrIndex,
7138                     spec,
7139                     numCols,
7140                     sizeof(spec[0]),
7141                     0,              // No special flags
7142                     true);          // default record
7143   if (rec == NULL)
7144   {
7145     free(pkMask);
7146     DBUG_RETURN(-1);
7147   }
7148 
7149   /* Store in the table definition */
7150   tableOrIndex->m_ndbrecord= rec;
7151   tableOrIndex->m_pkMask= pkMask;
7152 
7153   DBUG_RETURN(0);
7154 }
7155 
7156 /* This method initialises the data for a single
7157  * column in the passed NdbRecord structure
7158  */
7159 int
initialiseColumnData(bool isIndex,Uint32 flags,const NdbDictionary::RecordSpecification * recSpec,Uint32 colNum,NdbRecord * rec)7160 NdbDictionaryImpl::initialiseColumnData(bool isIndex,
7161                                         Uint32 flags,
7162                                         const NdbDictionary::RecordSpecification *recSpec,
7163                                         Uint32 colNum,
7164                                         NdbRecord *rec)
7165 {
7166   const NdbColumnImpl *col= &NdbColumnImpl::getImpl(*(recSpec->column));
7167   if (!col)
7168   {
7169     // Missing column specification in NdbDictionary::RecordSpecification
7170     m_error.code= 4290;
7171     return -1;
7172   }
7173 
7174   if (col->m_attrId & AttributeHeader::PSEUDO)
7175   {
7176     /* Pseudo columns not supported by NdbRecord */
7177     m_error.code= 4523;
7178     return -1;
7179   }
7180 
7181   if (col->m_indexSourced)
7182   {
7183     // Attempt to pass an index column to createRecord...
7184     m_error.code= 4540;
7185     return -1;
7186   }
7187 
7188   NdbRecord::Attr *recCol= &rec->columns[colNum];
7189   recCol->attrId= col->m_attrId;
7190   recCol->column_no= col->m_column_no;
7191   recCol->index_attrId= ~0;
7192   recCol->offset= recSpec->offset;
7193   recCol->maxSize= col->getSizeInBytesForRecord();
7194   recCol->orgAttrSize= col->m_orgAttrSize;
7195   if (recCol->offset+recCol->maxSize > rec->m_row_size)
7196     rec->m_row_size= recCol->offset+recCol->maxSize;
7197   recCol->charset_info= col->m_cs;
7198   recCol->compare_function= NdbSqlUtil::getType(col->m_type).m_cmp;
7199   recCol->flags= 0;
7200   if (!isIndex && col->m_pk)
7201     recCol->flags|= NdbRecord::IsKey;
7202   /* For indexes, we set key membership below. */
7203   if (col->m_storageType == NDB_STORAGETYPE_DISK)
7204     recCol->flags|= NdbRecord::IsDisk;
7205   if (col->m_nullable)
7206   {
7207     recCol->flags|= NdbRecord::IsNullable;
7208     recCol->nullbit_byte_offset= recSpec->nullbit_byte_offset;
7209     recCol->nullbit_bit_in_byte= recSpec->nullbit_bit_in_byte;
7210 
7211     const Uint32 nullbit_byte= recSpec->nullbit_byte_offset +
7212       (recSpec->nullbit_bit_in_byte >> 3);
7213     if (nullbit_byte >= rec->m_row_size)
7214       rec->m_row_size= nullbit_byte + 1;
7215   }
7216   if (col->m_arrayType==NDB_ARRAYTYPE_SHORT_VAR)
7217   {
7218     recCol->flags|= NdbRecord::IsVar1ByteLen;
7219     if (flags & NdbDictionary::RecMysqldShrinkVarchar)
7220       recCol->flags|= NdbRecord::IsMysqldShrinkVarchar;
7221   }
7222   else if (col->m_arrayType==NDB_ARRAYTYPE_MEDIUM_VAR)
7223   {
7224     recCol->flags|= NdbRecord::IsVar2ByteLen;
7225   }
7226   if (col->m_type == NdbDictionary::Column::Bit)
7227   {
7228     recCol->bitCount= col->m_length;
7229     if (flags & NdbDictionary::RecMysqldBitfield)
7230     {
7231       recCol->flags|= NdbRecord::IsMysqldBitfield;
7232       if (!(col->m_nullable))
7233       {
7234         /*
7235           We need these to access the overflow bits stored within
7236           the null bitmap.
7237         */
7238         recCol->nullbit_byte_offset= recSpec->nullbit_byte_offset;
7239         recCol->nullbit_bit_in_byte= recSpec->nullbit_bit_in_byte;
7240       }
7241       if ((flags & NdbDictionary::RecPerColumnFlags) &&
7242           (recSpec->column_flags &
7243              NdbDictionary::RecordSpecification::BitColMapsNullBitOnly))
7244       {
7245         /* Bitfield maps only null bit values. No overflow bits*/
7246         recCol->flags|= NdbRecord::BitFieldMapsNullBitOnly;
7247       }
7248     }
7249   }
7250   else
7251     recCol->bitCount= 0;
7252   if (col->m_distributionKey)
7253     recCol->flags|= NdbRecord::IsDistributionKey;
7254   if (col->getBlobType())
7255   {
7256     recCol->flags|= NdbRecord::IsBlob;
7257     rec->flags|= NdbRecord::RecHasBlob;
7258   }
7259   return 0;
7260 }
7261 
7262 /**
7263  * createRecordInternal
7264  * Create an NdbRecord object using the table implementation and
7265  * RecordSpecification array passed.
7266  * The table pointer may be a proper table, or the underlying
7267  * table of an Index.  In any case, it is assumed that is is a
7268  * global table object, which may be safely shared between
7269  * multiple threads.  The responsibility for ensuring that it is
7270  * a global object rests with the caller. Called internally by
7271  * the createRecord method
7272  */
7273 NdbRecord *
createRecordInternal(const NdbTableImpl * table,const NdbDictionary::RecordSpecification * recSpec,Uint32 length,Uint32 elemSize,Uint32 flags,bool defaultRecord)7274 NdbDictionaryImpl::createRecordInternal(const NdbTableImpl *table,
7275                                         const NdbDictionary::RecordSpecification *recSpec,
7276                                         Uint32 length,
7277                                         Uint32 elemSize,
7278                                         Uint32 flags,
7279                                         bool defaultRecord)
7280 {
7281   NdbRecord *rec= NULL;
7282   Uint32 numKeys, tableNumKeys, numIndexDistrKeys, min_distkey_prefix_length;
7283   Uint32 oldAttrId;
7284   bool isIndex;
7285   Uint32 i;
7286 
7287   if (!validateRecordSpec(recSpec, length, flags))
7288   {
7289     /* Error set in call */
7290     return NULL;
7291   }
7292 
7293   isIndex= (table->m_indexType==NdbDictionary::Object::OrderedIndex ||
7294             table->m_indexType==NdbDictionary::Object::UniqueHashIndex);
7295 
7296   /* Count the number of key columns in the table or index. */
7297   if (isIndex)
7298   {
7299     assert(table->m_index);
7300     /* Ignore the extra NDB$TNODE column at the end. */
7301     tableNumKeys= table->m_columns.size() - 1;
7302   }
7303   else
7304   {
7305     tableNumKeys= 0;
7306     for (i= 0; i<table->m_columns.size(); i++)
7307     {
7308       if (table->m_columns[i]->m_pk)
7309         tableNumKeys++;
7310     }
7311   }
7312   Uint32 tableNumDistKeys;
7313   if (isIndex || table->m_noOfDistributionKeys != 0)
7314     tableNumDistKeys= table->m_noOfDistributionKeys;
7315   else
7316     tableNumDistKeys= table->m_noOfKeys;
7317 
7318   int max_attrId = -1;
7319   for (i = 0; i < length; i++)
7320   {
7321     Uint32 attrId = recSpec[i].column->getAttrId();
7322     if ((int)attrId > max_attrId)
7323       max_attrId = (int)attrId;
7324   }
7325   Uint32 attrId_indexes_length = (Uint32)(max_attrId + 1);
7326 
7327   /*
7328     We need to allocate space for
7329      1. The struct itself.
7330      2. The columns[] array at the end of struct (length #columns).
7331      3. An extra Uint32 array key_indexes (length #key columns).
7332      4. An extra Uint32 array distkey_indexes (length #distribution keys).
7333      5. An extra int array attrId_indexes (length max attrId)
7334   */
7335   const Uint32 ndbRecBytes= sizeof(NdbRecord);
7336   const Uint32 colArrayBytes= length*sizeof(NdbRecord::Attr);
7337   const Uint32 tableKeyMapBytes= tableNumKeys*sizeof(Uint32);
7338   const Uint32 tableDistKeyMapBytes= tableNumDistKeys*sizeof(Uint32);
7339   const Uint32 attrIdMapBytes= (attrId_indexes_length + 1)*sizeof(int);
7340   rec= (NdbRecord *)calloc(1, ndbRecBytes +
7341                               colArrayBytes +
7342                               tableKeyMapBytes +
7343                               tableDistKeyMapBytes +
7344                               attrIdMapBytes);
7345   if (!rec)
7346   {
7347     m_error.code= 4000;
7348     return NULL;
7349   }
7350   Uint32 *key_indexes= (Uint32 *)((unsigned char *)rec +
7351                                   ndbRecBytes +
7352                                   colArrayBytes);
7353   Uint32 *distkey_indexes= (Uint32 *)((unsigned char *)rec +
7354                                       ndbRecBytes +
7355                                       colArrayBytes +
7356                                       tableKeyMapBytes);
7357   int *attrId_indexes = (int *)((unsigned char *)rec +
7358                                 ndbRecBytes +
7359                                 colArrayBytes +
7360                                 tableKeyMapBytes +
7361                                 tableDistKeyMapBytes);
7362   /**
7363    * We overallocate one word of attribute index words. This is to be able
7364    * to speed up receive_packed_ndbrecord by reading ahead, the value we read
7365    * there will never be used, but to ensure we don't crash because of it we
7366    * allocate a word and set it to -1.
7367    */
7368   for (i = 0; i < (attrId_indexes_length + 1); i++)
7369   {
7370     attrId_indexes[i] = -1;
7371   }
7372 
7373   rec->table= table;
7374   rec->tableId= table->m_id;
7375   rec->tableVersion= table->m_version;
7376   rec->flags= 0;
7377   rec->noOfColumns= length;
7378   rec->m_no_of_distribution_keys= tableNumDistKeys;
7379 
7380   /* Check for any blobs in the base table. */
7381   for (i= 0; i<table->m_columns.size(); i++)
7382   {
7383     if (table->m_columns[i]->getBlobType())
7384     {
7385       rec->flags|= NdbRecord::RecTableHasBlob;
7386       break;
7387     }
7388   }
7389 
7390   rec->m_row_size= 0;
7391   for (i= 0; i<length; i++)
7392   {
7393     const NdbDictionary::RecordSpecification *rs= &recSpec[i];
7394 
7395     /* Initialise this column in NdbRecord from column
7396      * info
7397      */
7398     if (initialiseColumnData(isIndex,
7399                              flags,
7400                              rs,
7401                              i,
7402                              rec) != 0)
7403       goto err;
7404 
7405     /*
7406       Distibution key flag for unique index needs to be corrected
7407       to reflect the keys in the index base table
7408     */
7409     if (table->m_indexType == NdbDictionary::Object::UniqueHashIndex)
7410     {
7411       NdbRecord::Attr *recCol= &rec->columns[i];
7412       if (table->m_columns[i]->m_distributionKey)
7413         recCol->flags|= NdbRecord::IsDistributionKey;
7414       else
7415         recCol->flags&= ~NdbRecord::IsDistributionKey;
7416     }
7417   }
7418 
7419   /* Now we sort the array in attrId order. */
7420   qsort(rec->columns,
7421         rec->noOfColumns,
7422         sizeof(rec->columns[0]),
7423         cmp_ndbrec_attr);
7424 
7425   /*
7426     Now check for the presence of primary keys, and set flags for whether
7427     this NdbRecord can be used for insert and/or for specifying keys for
7428     read/update.
7429 
7430     Also test for duplicate columns, easy now that they are sorted.
7431     Also set up key_indexes array.
7432     Also compute if an index includes all of the distribution key.
7433     Also set up distkey_indexes array.
7434   */
7435 
7436   oldAttrId= ~0;
7437   numKeys= 0;
7438   min_distkey_prefix_length= 0;
7439   numIndexDistrKeys= 0;
7440   for (i= 0; i<rec->noOfColumns; i++)
7441   {
7442     NdbRecord::Attr *recCol= &rec->columns[i];
7443     if (i > 0 && oldAttrId==recCol->attrId)
7444     {
7445       m_error.code= 4291;
7446       goto err;
7447     }
7448     oldAttrId= recCol->attrId;
7449 
7450     assert(recCol->attrId < attrId_indexes_length);
7451     attrId_indexes[recCol->attrId] = i;
7452 
7453     if (isIndex)
7454     {
7455       Uint32 colNo= recCol->column_no;
7456       int key_idx;
7457       if (colNo < table->m_index->m_key_ids.size() &&
7458           (key_idx= table->m_index->m_key_ids[colNo]) != -1)
7459       {
7460         assert((Uint32)key_idx < tableNumKeys);
7461         recCol->flags|= NdbRecord::IsKey;
7462         key_indexes[key_idx]= i;
7463         recCol->index_attrId= table->m_columns[key_idx]->m_attrId;
7464         numKeys++;
7465 
7466         if (recCol->flags & NdbRecord::IsDistributionKey)
7467         {
7468           if (min_distkey_prefix_length <= (Uint32)key_idx)
7469             min_distkey_prefix_length= key_idx+1;
7470           if (numIndexDistrKeys < tableNumDistKeys)
7471             distkey_indexes[numIndexDistrKeys++]= i;
7472         }
7473       }
7474     }
7475     else
7476     {
7477       if (recCol->flags & NdbRecord::IsKey)
7478       {
7479         key_indexes[numKeys]= i;
7480         numKeys++;
7481       }
7482       if (recCol->flags & NdbRecord::IsDistributionKey)
7483       {
7484         if (numIndexDistrKeys < tableNumDistKeys)
7485           distkey_indexes[numIndexDistrKeys++]= i;
7486       }
7487     }
7488   }
7489   if (defaultRecord)
7490     rec->flags|= NdbRecord::RecIsDefaultRec;
7491 
7492   rec->key_indexes= key_indexes;
7493   rec->key_index_length= tableNumKeys;
7494   rec->m_min_distkey_prefix_length= min_distkey_prefix_length;
7495   rec->distkey_indexes= distkey_indexes;
7496   rec->distkey_index_length= numIndexDistrKeys;
7497   rec->m_attrId_indexes = attrId_indexes;
7498   rec->m_attrId_indexes_length = attrId_indexes_length;
7499 
7500   /*
7501     Since we checked for duplicates, we can check for primary key completeness
7502     simply by counting.
7503   */
7504   if (numKeys == tableNumKeys)
7505   {
7506     rec->flags|= NdbRecord::RecHasAllKeys;
7507     if (rec->noOfColumns == tableNumKeys)
7508       rec->flags|= NdbRecord::RecIsKeyRecord;
7509   }
7510   if (isIndex)
7511     rec->flags|= NdbRecord::RecIsIndex;
7512   rec->m_keyLenInWords= table->m_keyLenInWords;
7513 
7514   if (table->m_fragmentType == NdbDictionary::Object::UserDefined)
7515     rec->flags |= NdbRecord::RecHasUserDefinedPartitioning;
7516 
7517   return rec;
7518 
7519  err:
7520   if (rec)
7521     free(rec);
7522   return NULL;
7523 }
7524 
7525 /**
7526  * createRecord
7527  * Create an NdbRecord object using the table implementation and
7528  * RecordSpecification array passed.
7529  * The table pointer may be a proper table, or the underlying
7530  * table of an Index.  In any case, it is assumed that is is a
7531  * global table object, which may be safely shared between
7532  * multiple threads.  The responsibility for ensuring that it is
7533  * a global object rests with the caller. Method validates the
7534  * version of the sent RecordSpecification instance, maps it to
7535  * a newer version if necessary and internally calls
7536  * createRecordInternal to do the processing
7537  */
7538 NdbRecord *
createRecord(const NdbTableImpl * table,const NdbDictionary::RecordSpecification * recSpec,Uint32 length,Uint32 elemSize,Uint32 flags,bool defaultRecord)7539 NdbDictionaryImpl::createRecord(const NdbTableImpl *table,
7540                                 const NdbDictionary::RecordSpecification *recSpec,
7541                                 Uint32 length,
7542                                 Uint32 elemSize,
7543                                 Uint32 flags,
7544                                 bool defaultRecord)
7545 {
7546   NdbDictionary::RecordSpecification *newRecordSpec = NULL;
7547 
7548   /* Check if recSpec is an instance of the newer version */
7549   if (elemSize != sizeof(NdbDictionary::RecordSpecification))
7550   {
7551     if(elemSize == sizeof(NdbDictionary::RecordSpecification_v1))
7552     {
7553       /*
7554         Older RecordSpecification in use.
7555         Map it to an instance of newer version.
7556       */
7557       const NdbDictionary::RecordSpecification_v1* oldRecordSpec =
7558           (const NdbDictionary::RecordSpecification_v1*) recSpec;
7559 
7560       newRecordSpec =(NdbDictionary::RecordSpecification*)
7561                       NdbMem_Allocate(length *
7562                         sizeof(NdbDictionary::RecordSpecification));
7563       if(newRecordSpec == NULL)
7564       {
7565         m_error.code= 4000;
7566         return NULL;
7567       }
7568       for (Uint32 i= 0; i < length; i++)
7569       {
7570         /* map values from older version to newer version */
7571         newRecordSpec[i].column = oldRecordSpec[i].column;
7572         newRecordSpec[i].offset = oldRecordSpec[i].offset;
7573         newRecordSpec[i].nullbit_byte_offset =
7574             oldRecordSpec[i].nullbit_byte_offset;
7575         newRecordSpec[i].nullbit_bit_in_byte =
7576             oldRecordSpec[i].nullbit_bit_in_byte;
7577         newRecordSpec[i].column_flags = 0;
7578       }
7579       recSpec = &newRecordSpec[0];
7580     }
7581     else
7582     {
7583       m_error.code= 4289;
7584       return NULL;
7585     }
7586   }
7587   NdbRecord *ndbRec = createRecordInternal(table,
7588                                            recSpec,
7589                                            length,
7590                                            elemSize,
7591                                            flags,
7592                                            defaultRecord);
7593   NdbMem_Free((void*)newRecordSpec);
7594   return ndbRec;
7595 }
7596 
7597 void
copyMask(Uint32 * dst,const unsigned char * src) const7598 NdbRecord::copyMask(Uint32 *dst, const unsigned char *src) const
7599 {
7600   Uint32 i;
7601 
7602   BitmaskImpl::clear((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5, dst);
7603   if (src)
7604   {
7605     for (i= 0; i<noOfColumns; i++)
7606     {
7607       Uint32 attrId= columns[i].attrId;
7608 
7609       assert(!(attrId & AttributeHeader::PSEUDO));
7610 
7611       if (src[attrId>>3] & (1 << (attrId&7)))
7612         BitmaskImpl::set((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5, dst, attrId);
7613     }
7614   }
7615   else
7616   {
7617     for (i= 0; i<noOfColumns; i++)
7618     {
7619       Uint32 attrId= columns[i].attrId;
7620 
7621       assert(!(attrId & AttributeHeader::PSEUDO));
7622 
7623       BitmaskImpl::set((NDB_MAX_ATTRIBUTES_IN_TABLE+31)>>5, dst, attrId);
7624     }
7625   }
7626 }
7627 
7628 void
get_mysqld_bitfield(const char * src_row,char * dst_buffer) const7629 NdbRecord::Attr::get_mysqld_bitfield(const char *src_row, char *dst_buffer) const
7630 {
7631   assert(flags & IsMysqldBitfield);
7632   Uint64 bits;
7633   Uint32 remaining_bits= bitCount;
7634   Uint32 fractional_bitcount= remaining_bits % 8;
7635 
7636   /* Copy fractional bits, if any. */
7637   if (fractional_bitcount > 0 &&
7638       !(flags & BitFieldMapsNullBitOnly))
7639   {
7640     Uint32 fractional_shift= nullbit_bit_in_byte + ((flags & IsNullable) != 0);
7641     Uint32 fractional_bits= (unsigned char)(src_row[nullbit_byte_offset]);
7642     if (fractional_shift + fractional_bitcount > 8)
7643       fractional_bits|= (unsigned char)(src_row[nullbit_byte_offset+1]) << 8;
7644     fractional_bits=
7645       (fractional_bits >> fractional_shift) & ((1 << fractional_bitcount) - 1);
7646     bits= fractional_bits;
7647   }
7648   else
7649     bits= 0;
7650 
7651   /* Copy whole bytes. The mysqld format stored bit fields big-endian. */
7652   assert(remaining_bits <= 64);
7653   const unsigned char *src_ptr= (const unsigned char *)&src_row[offset];
7654   while (remaining_bits >= 8)
7655   {
7656     bits= (bits << 8) | (*src_ptr++);
7657     remaining_bits-= 8;
7658   }
7659 
7660   Uint32 small_bits= (Uint32)bits;
7661   memcpy(dst_buffer, &small_bits, 4);
7662   if (maxSize > 4)
7663   {
7664     small_bits= (Uint32)(bits >> 32);
7665     memcpy(dst_buffer+4, &small_bits, 4);
7666   }
7667 }
7668 
7669 void
put_mysqld_bitfield(char * dst_row,const char * src_buffer) const7670 NdbRecord::Attr::put_mysqld_bitfield(char *dst_row, const char *src_buffer) const
7671 {
7672   assert(flags & IsMysqldBitfield);
7673   char *dst_ptr= &dst_row[offset];
7674   Uint64 bits;
7675   Uint32 small_bits;
7676   memcpy(&small_bits, src_buffer, 4);
7677   bits= small_bits;
7678   if (maxSize > 4)
7679   {
7680     memcpy(&small_bits, src_buffer+4, 4);
7681     bits|= ((Uint64)small_bits) << 32;
7682   }
7683 
7684   /* Copy whole bytes. The mysqld format stores bitfields big-endian. */
7685   Uint32 remaining_bits= bitCount;
7686   assert(remaining_bits <= 64);
7687   dst_ptr+= remaining_bits/8;
7688   while (remaining_bits >= 8)
7689   {
7690     *--dst_ptr= (char)(bits & 0xff);
7691     bits>>= 8;
7692     remaining_bits-= 8;
7693   }
7694 
7695   /* Copy fractional bits, if any. */
7696   if (remaining_bits > 0 &&
7697       !(flags & BitFieldMapsNullBitOnly))
7698   {
7699     Uint32 shift= nullbit_bit_in_byte + ((flags & IsNullable) != 0);
7700     Uint32 mask= ((1 << remaining_bits) - 1) << shift;
7701     bits= (bits << shift) & mask;
7702     dst_row[nullbit_byte_offset]=
7703       Uint8((dst_row[nullbit_byte_offset] & ~mask) | bits);
7704     if (shift + remaining_bits > 8)
7705     {
7706       mask>>= 8;
7707       bits>>= 8;
7708       dst_row[nullbit_byte_offset+1]=
7709         Uint8((dst_row[nullbit_byte_offset+1] & ~mask) | bits);
7710     }
7711   }
7712 }
7713 
releaseRecord_impl(NdbRecord * rec)7714 void NdbDictionaryImpl::releaseRecord_impl(NdbRecord *rec)
7715 {
7716   if (rec)
7717   {
7718     /* Silently do nothing if they've passed the default
7719      * record in (similar to null handling behaviour)
7720      */
7721     if (!(rec->flags & NdbRecord::RecIsDefaultRec))
7722     {
7723       /* For non-default records, we need to release the
7724        * global table / index reference
7725        */
7726       if (rec->flags & NdbRecord::RecIsIndex)
7727         releaseIndexGlobal(*rec->table->m_index,
7728                            false); // Don't invalidate
7729       else
7730         releaseTableGlobal(*rec->table,
7731                            false); // Don't invalidate
7732 
7733       free(rec);
7734     }
7735   }
7736 }
7737 
7738 NdbDictionary::RecordType
getRecordType(const NdbRecord * record)7739 NdbDictionaryImpl::getRecordType(const NdbRecord* record)
7740 {
7741   if (record->flags & NdbRecord::RecIsIndex)
7742     return NdbDictionary::IndexAccess;
7743   else
7744     return NdbDictionary::TableAccess;
7745 }
7746 
7747 const char*
getRecordTableName(const NdbRecord * record)7748 NdbDictionaryImpl::getRecordTableName(const NdbRecord* record)
7749 {
7750   if (!(record->flags & NdbRecord::RecIsIndex))
7751   {
7752     return record->table->m_externalName.c_str();
7753   }
7754 
7755   return NULL;
7756 }
7757 
7758 const char*
getRecordIndexName(const NdbRecord * record)7759 NdbDictionaryImpl::getRecordIndexName(const NdbRecord* record)
7760 {
7761   if (record->flags & NdbRecord::RecIsIndex)
7762   {
7763     assert(record->table->m_index != NULL);
7764     assert(record->table->m_index->m_facade != NULL);
7765 
7766     return record->table->m_index->m_externalName.c_str();
7767   }
7768 
7769   return NULL;
7770 }
7771 
7772 bool
getNextAttrIdFrom(const NdbRecord * record,Uint32 startAttrId,Uint32 & nextAttrId)7773 NdbDictionaryImpl::getNextAttrIdFrom(const NdbRecord* record,
7774                                      Uint32 startAttrId,
7775                                      Uint32& nextAttrId)
7776 {
7777   for (Uint32 i= startAttrId; i < record->m_attrId_indexes_length; i++)
7778   {
7779     if (record->m_attrId_indexes[i] != -1)
7780     {
7781       nextAttrId= i;
7782       return true;
7783     }
7784   }
7785   return false;
7786 }
7787 
7788 bool
getOffset(const NdbRecord * record,Uint32 attrId,Uint32 & offset)7789 NdbDictionaryImpl::getOffset(const NdbRecord* record,
7790                              Uint32 attrId,
7791                              Uint32& offset)
7792 {
7793   if (attrId < record->m_attrId_indexes_length)
7794   {
7795     int attrIdIndex= record->m_attrId_indexes[attrId];
7796 
7797     if (attrIdIndex != -1)
7798     {
7799       assert(attrIdIndex < (int) record->noOfColumns);
7800 
7801       offset= record->columns[attrIdIndex].offset;
7802       return true;
7803     }
7804   }
7805 
7806   /* AttrId not part of this NdbRecord */
7807   return false;
7808 }
7809 
7810 bool
getNullBitOffset(const NdbRecord * record,Uint32 attrId,Uint32 & nullbit_byte_offset,Uint32 & nullbit_bit_in_byte)7811 NdbDictionaryImpl::getNullBitOffset(const NdbRecord* record,
7812                                     Uint32 attrId,
7813                                     Uint32& nullbit_byte_offset,
7814                                     Uint32& nullbit_bit_in_byte)
7815 {
7816   if (attrId < record->m_attrId_indexes_length)
7817   {
7818     int attrIdIndex= record->m_attrId_indexes[attrId];
7819 
7820     if (attrIdIndex != -1)
7821     {
7822       assert(attrIdIndex < (int) record->noOfColumns);
7823 
7824       NdbRecord::Attr attr= record->columns[attrIdIndex];
7825 
7826       nullbit_byte_offset= attr.nullbit_byte_offset;
7827       nullbit_bit_in_byte= attr.nullbit_bit_in_byte;
7828       return true;
7829     }
7830   }
7831 
7832   /* AttrId not part of this NdbRecord */
7833   return false;
7834 }
7835 
7836 const char*
getValuePtr(const NdbRecord * record,const char * row,Uint32 attrId)7837 NdbDictionaryImpl::getValuePtr(const NdbRecord* record,
7838                                const char* row,
7839                                Uint32 attrId)
7840 {
7841   if (attrId < record->m_attrId_indexes_length)
7842   {
7843     int attrIdIndex= record->m_attrId_indexes[attrId];
7844 
7845     if (attrIdIndex != -1)
7846     {
7847       assert(attrIdIndex < (int) record->noOfColumns);
7848 
7849       return row + (record->columns[attrIdIndex].offset);
7850     }
7851   }
7852 
7853   /* AttrId not part of this NdbRecord */
7854   return NULL;
7855 }
7856 
7857 char*
getValuePtr(const NdbRecord * record,char * row,Uint32 attrId)7858 NdbDictionaryImpl::getValuePtr(const NdbRecord* record,
7859                                char* row,
7860                                Uint32 attrId)
7861 {
7862   if (attrId < record->m_attrId_indexes_length)
7863   {
7864     int attrIdIndex= record->m_attrId_indexes[attrId];
7865 
7866     if (attrIdIndex != -1)
7867     {
7868       assert(attrIdIndex < (int)record->noOfColumns);
7869 
7870       return row + (record->columns[attrIdIndex].offset);
7871     }
7872   }
7873 
7874   /* AttrId not part of this NdbRecord */
7875   return NULL;
7876 }
7877 
7878 bool
isNull(const NdbRecord * record,const char * row,Uint32 attrId)7879 NdbDictionaryImpl::isNull(const NdbRecord* record,
7880                           const char* row,
7881                           Uint32 attrId)
7882 {
7883   if (attrId < record->m_attrId_indexes_length)
7884   {
7885     int attrIdIndex= record->m_attrId_indexes[attrId];
7886 
7887     if (attrIdIndex != -1)
7888     {
7889       assert(attrIdIndex < (int)record->noOfColumns);
7890       return record->columns[attrIdIndex].is_null(row);
7891     }
7892   }
7893 
7894   /* AttrId not part of this NdbRecord or is not nullable */
7895   return false;
7896 }
7897 
7898 int
setNull(const NdbRecord * record,char * row,Uint32 attrId,bool value)7899 NdbDictionaryImpl::setNull(const NdbRecord* record,
7900                            char* row,
7901                            Uint32 attrId,
7902                            bool value)
7903 {
7904   if (attrId < record->m_attrId_indexes_length)
7905   {
7906     int attrIdIndex= record->m_attrId_indexes[attrId];
7907 
7908     if (attrIdIndex != -1)
7909     {
7910       assert(attrIdIndex < (int)record->noOfColumns);
7911       NdbRecord::Attr attr= record->columns[attrIdIndex];
7912 
7913       if (attr.flags & NdbRecord::IsNullable)
7914       {
7915         if (value)
7916           *(row + attr.nullbit_byte_offset) |=
7917             (1 << attr.nullbit_bit_in_byte);
7918         else
7919           *(row + attr.nullbit_byte_offset) &=
7920             ~(1 << attr.nullbit_bit_in_byte);
7921 
7922         return 0;
7923       }
7924     }
7925   }
7926 
7927   /* AttrId not part of this NdbRecord or is not nullable */
7928   return -1;
7929 }
7930 
7931 Uint32
getRecordRowLength(const NdbRecord * record)7932 NdbDictionaryImpl::getRecordRowLength(const NdbRecord* record)
7933 {
7934   return record->m_row_size;
7935 }
7936 
7937 
7938 
7939 int
create_file(const NdbFileImpl & file,const NdbFilegroupImpl & group,bool overwrite,NdbDictObjectImpl * obj)7940 NdbDictInterface::create_file(const NdbFileImpl & file,
7941 			      const NdbFilegroupImpl & group,
7942 			      bool overwrite,
7943 			      NdbDictObjectImpl* obj)
7944 {
7945   DBUG_ENTER("NdbDictInterface::create_file");
7946   UtilBufferWriter w(m_buffer);
7947   DictFilegroupInfo::File f; f.init();
7948   BaseString::snprintf(f.FileName, sizeof(f.FileName), "%s", file.m_path.c_str());
7949   f.FileType = file.m_type;
7950   f.FilegroupId = group.m_id;
7951   f.FilegroupVersion = group.m_version;
7952   f.FileSizeHi = (Uint32)(file.m_size >> 32);
7953   f.FileSizeLo = (Uint32)(file.m_size & 0xFFFFFFFF);
7954 
7955   SimpleProperties::UnpackStatus s;
7956   s = SimpleProperties::pack(w,
7957 			     &f,
7958 			     DictFilegroupInfo::FileMapping,
7959 			     DictFilegroupInfo::FileMappingSize, true);
7960 
7961   if(s != SimpleProperties::Eof){
7962     abort();
7963   }
7964 
7965   NdbApiSignal tSignal(m_reference);
7966   tSignal.theReceiversBlockNumber = DBDICT;
7967   tSignal.theVerId_signalNumber = GSN_CREATE_FILE_REQ;
7968   tSignal.theLength = CreateFileReq::SignalLength;
7969 
7970   CreateFileReq* req = CAST_PTR(CreateFileReq, tSignal.getDataPtrSend());
7971   req->senderRef = m_reference;
7972   req->senderData = 0;
7973   req->objType = file.m_type;
7974   req->requestInfo = 0;
7975   if (overwrite)
7976     req->requestInfo |= CreateFileReq::ForceCreateFile;
7977   req->requestInfo |= m_tx.requestFlags();
7978   req->transId = m_tx.transId();
7979   req->transKey = m_tx.transKey();
7980 
7981   LinearSectionPtr ptr[3];
7982   ptr[0].p = (Uint32*)m_buffer.get_data();
7983   ptr[0].sz = m_buffer.length() / 4;
7984 
7985   int err[] = { CreateFileRef::Busy, CreateFileRef::NotMaster, 0};
7986   /*
7987     Send signal without time-out since creating files can take a very long
7988     time if the file is very big.
7989   */
7990   int ret = dictSignal(&tSignal, ptr, 1,
7991 		       0, // master
7992 		       WAIT_CREATE_INDX_REQ,
7993 		       -1, 100,
7994 		       err);
7995 
7996   if (ret == 0)
7997   {
7998     Uint32* data = (Uint32*)m_buffer.get_data();
7999     if (obj)
8000     {
8001       obj->m_id = data[0];
8002       obj->m_version = data[1];
8003     }
8004     m_warn = data[2];
8005     DBUG_PRINT("info", ("warning flags: 0x%x", m_warn));
8006   }
8007 
8008   DBUG_RETURN(ret);
8009 }
8010 
8011 void
execCREATE_FILE_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8012 NdbDictInterface::execCREATE_FILE_CONF(const NdbApiSignal * signal,
8013 				       const LinearSectionPtr ptr[3])
8014 {
8015   DBUG_ENTER("NdbDictInterface::execCREATE_FILE_CONF");
8016   const CreateFileConf* conf=
8017     CAST_CONSTPTR(CreateFileConf, signal->getDataPtr());
8018   m_buffer.grow(4 * 3); // 3 words
8019   Uint32* data = (Uint32*)m_buffer.get_data();
8020   data[0] = conf->fileId;
8021   data[1] = conf->fileVersion;
8022   data[2] = conf->warningFlags;
8023 
8024   m_impl->theWaiter.signal(NO_WAIT);
8025   DBUG_VOID_RETURN;
8026 }
8027 
8028 void
execCREATE_FILE_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8029 NdbDictInterface::execCREATE_FILE_REF(const NdbApiSignal * signal,
8030 				      const LinearSectionPtr ptr[3])
8031 {
8032   DBUG_ENTER("NdbDictInterface::execCREATE_FILE_REF");
8033   const CreateFileRef* ref =
8034     CAST_CONSTPTR(CreateFileRef, signal->getDataPtr());
8035   m_error.code = ref->errorCode;
8036   DBUG_PRINT("info", ("Error code = %d", m_error.code));
8037   m_masterNodeId = ref->masterNodeId;
8038   m_impl->theWaiter.signal(NO_WAIT);
8039   DBUG_VOID_RETURN;
8040 }
8041 
8042 int
drop_file(const NdbFileImpl & file)8043 NdbDictInterface::drop_file(const NdbFileImpl & file)
8044 {
8045   DBUG_ENTER("NdbDictInterface::drop_file");
8046   NdbApiSignal tSignal(m_reference);
8047   tSignal.theReceiversBlockNumber = DBDICT;
8048   tSignal.theVerId_signalNumber = GSN_DROP_FILE_REQ;
8049   tSignal.theLength = DropFileReq::SignalLength;
8050 
8051   DropFileReq* req = CAST_PTR(DropFileReq, tSignal.getDataPtrSend());
8052   req->senderRef = m_reference;
8053   req->senderData = 0;
8054   req->file_id = file.m_id;
8055   req->file_version = file.m_version;
8056   req->requestInfo = 0;
8057   req->requestInfo |= m_tx.requestFlags();
8058   req->transId = m_tx.transId();
8059   req->transKey = m_tx.transKey();
8060 
8061   int err[] = { DropFileRef::Busy, DropFileRef::NotMaster, 0};
8062   DBUG_RETURN(dictSignal(&tSignal, 0, 0,
8063 	                 0, // master
8064 		         WAIT_CREATE_INDX_REQ,
8065 		         DICT_WAITFOR_TIMEOUT, 100,
8066 		         err));
8067 }
8068 
8069 void
execDROP_FILE_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8070 NdbDictInterface::execDROP_FILE_CONF(const NdbApiSignal * signal,
8071 					    const LinearSectionPtr ptr[3])
8072 {
8073   DBUG_ENTER("NdbDictInterface::execDROP_FILE_CONF");
8074   m_impl->theWaiter.signal(NO_WAIT);
8075   DBUG_VOID_RETURN;
8076 }
8077 
8078 void
execDROP_FILE_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8079 NdbDictInterface::execDROP_FILE_REF(const NdbApiSignal * signal,
8080 					   const LinearSectionPtr ptr[3])
8081 {
8082   DBUG_ENTER("NdbDictInterface::execDROP_FILE_REF");
8083   const DropFileRef* ref =
8084     CAST_CONSTPTR(DropFileRef, signal->getDataPtr());
8085   m_error.code = ref->errorCode;
8086   DBUG_PRINT("info", ("Error code = %d", m_error.code));
8087   m_masterNodeId = ref->masterNodeId;
8088   m_impl->theWaiter.signal(NO_WAIT);
8089   DBUG_VOID_RETURN;
8090 }
8091 
8092 int
create_filegroup(const NdbFilegroupImpl & group,NdbDictObjectImpl * obj)8093 NdbDictInterface::create_filegroup(const NdbFilegroupImpl & group,
8094 				   NdbDictObjectImpl* obj)
8095 {
8096   DBUG_ENTER("NdbDictInterface::create_filegroup");
8097   UtilBufferWriter w(m_buffer);
8098   DictFilegroupInfo::Filegroup fg; fg.init();
8099   BaseString::snprintf(fg.FilegroupName, sizeof(fg.FilegroupName),
8100            "%s", group.m_name.c_str());
8101   switch(group.m_type){
8102   case NdbDictionary::Object::Tablespace:
8103   {
8104     fg.FilegroupType = DictTabInfo::Tablespace;
8105     //fg.TS_DataGrow = group.m_grow_spec;
8106     fg.TS_ExtentSize = group.m_extent_size;
8107 
8108     if(group.m_logfile_group_version != ~(Uint32)0)
8109     {
8110       fg.TS_LogfileGroupId = group.m_logfile_group_id;
8111       fg.TS_LogfileGroupVersion = group.m_logfile_group_version;
8112     }
8113     else
8114     {
8115       NdbLogfileGroupImpl tmp;
8116       if(get_filegroup(tmp, NdbDictionary::Object::LogfileGroup,
8117 		       group.m_logfile_group_name.c_str()) == 0)
8118       {
8119 	fg.TS_LogfileGroupId = tmp.m_id;
8120 	fg.TS_LogfileGroupVersion = tmp.m_version;
8121       }
8122       else // error set by get filegroup
8123       {
8124 	DBUG_RETURN(-1);
8125       }
8126     }
8127   }
8128   break;
8129   case NdbDictionary::Object::LogfileGroup:
8130     fg.LF_UndoBufferSize = group.m_undo_buffer_size;
8131     fg.FilegroupType = DictTabInfo::LogfileGroup;
8132     //fg.LF_UndoGrow = group.m_grow_spec;
8133     break;
8134   default:
8135     abort();
8136     DBUG_RETURN(-1);
8137   };
8138 
8139   SimpleProperties::UnpackStatus s;
8140   s = SimpleProperties::pack(w,
8141 			     &fg,
8142 			     DictFilegroupInfo::Mapping,
8143 			     DictFilegroupInfo::MappingSize, true);
8144 
8145   if(s != SimpleProperties::Eof){
8146     abort();
8147   }
8148 
8149   NdbApiSignal tSignal(m_reference);
8150   tSignal.theReceiversBlockNumber = DBDICT;
8151   tSignal.theVerId_signalNumber = GSN_CREATE_FILEGROUP_REQ;
8152   tSignal.theLength = CreateFilegroupReq::SignalLength;
8153 
8154   CreateFilegroupReq* req =
8155     CAST_PTR(CreateFilegroupReq, tSignal.getDataPtrSend());
8156   req->senderRef = m_reference;
8157   req->senderData = 0;
8158   req->objType = fg.FilegroupType;
8159   req->requestInfo = 0;
8160   req->requestInfo |= m_tx.requestFlags();
8161   req->transId = m_tx.transId();
8162   req->transKey = m_tx.transKey();
8163 
8164   LinearSectionPtr ptr[3];
8165   ptr[0].p = (Uint32*)m_buffer.get_data();
8166   ptr[0].sz = m_buffer.length() / 4;
8167 
8168   int err[] = { CreateFilegroupRef::Busy, CreateFilegroupRef::NotMaster, 0};
8169   int ret = dictSignal(&tSignal, ptr, 1,
8170 		       0, // master
8171 		       WAIT_CREATE_INDX_REQ,
8172 		       DICT_WAITFOR_TIMEOUT, 100,
8173 		       err);
8174 
8175   if (ret == 0)
8176   {
8177     Uint32* data = (Uint32*)m_buffer.get_data();
8178     if (obj)
8179     {
8180       obj->m_id = data[0];
8181       obj->m_version = data[1];
8182     }
8183     m_warn = data[2];
8184     DBUG_PRINT("info", ("warning flags: 0x%x", m_warn));
8185   }
8186 
8187   DBUG_RETURN(ret);
8188 }
8189 
8190 void
execCREATE_FILEGROUP_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8191 NdbDictInterface::execCREATE_FILEGROUP_CONF(const NdbApiSignal * signal,
8192 					    const LinearSectionPtr ptr[3])
8193 {
8194   DBUG_ENTER("execCREATE_FILEGROUP_CONF");
8195   const CreateFilegroupConf* conf=
8196     CAST_CONSTPTR(CreateFilegroupConf, signal->getDataPtr());
8197   m_buffer.grow(4 * 3); // 3 words
8198   Uint32* data = (Uint32*)m_buffer.get_data();
8199   data[0] = conf->filegroupId;
8200   data[1] = conf->filegroupVersion;
8201   data[2] = conf->warningFlags;
8202   m_impl->theWaiter.signal(NO_WAIT);
8203   DBUG_VOID_RETURN;
8204 }
8205 
8206 void
execCREATE_FILEGROUP_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8207 NdbDictInterface::execCREATE_FILEGROUP_REF(const NdbApiSignal * signal,
8208 					   const LinearSectionPtr ptr[3])
8209 {
8210   DBUG_ENTER("NdbDictInterface::execCREATE_FILEGROUP_REF");
8211   const CreateFilegroupRef* ref =
8212     CAST_CONSTPTR(CreateFilegroupRef, signal->getDataPtr());
8213   m_error.code = ref->errorCode;
8214   DBUG_PRINT("info", ("Error code = %d", m_error.code));
8215   m_masterNodeId = ref->masterNodeId;
8216   m_impl->theWaiter.signal(NO_WAIT);
8217   DBUG_VOID_RETURN;
8218 }
8219 
8220 int
drop_filegroup(const NdbFilegroupImpl & group)8221 NdbDictInterface::drop_filegroup(const NdbFilegroupImpl & group)
8222 {
8223   DBUG_ENTER("NdbDictInterface::drop_filegroup");
8224   NdbApiSignal tSignal(m_reference);
8225   tSignal.theReceiversBlockNumber = DBDICT;
8226   tSignal.theVerId_signalNumber = GSN_DROP_FILEGROUP_REQ;
8227   tSignal.theLength = DropFilegroupReq::SignalLength;
8228 
8229   DropFilegroupReq* req = CAST_PTR(DropFilegroupReq, tSignal.getDataPtrSend());
8230   req->senderRef = m_reference;
8231   req->senderData = 0;
8232   req->filegroup_id = group.m_id;
8233   req->filegroup_version = group.m_version;
8234   req->requestInfo = 0;
8235   req->requestInfo |= m_tx.requestFlags();
8236   req->transId = m_tx.transId();
8237   req->transKey = m_tx.transKey();
8238 
8239   int err[] = { DropFilegroupRef::Busy, DropFilegroupRef::NotMaster, 0};
8240   DBUG_RETURN(dictSignal(&tSignal, 0, 0,
8241                          0, // master
8242 		         WAIT_CREATE_INDX_REQ,
8243 		         DICT_WAITFOR_TIMEOUT, 100,
8244 		         err));
8245 }
8246 
8247 void
execDROP_FILEGROUP_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8248 NdbDictInterface::execDROP_FILEGROUP_CONF(const NdbApiSignal * signal,
8249 					    const LinearSectionPtr ptr[3])
8250 {
8251   DBUG_ENTER("NdbDictInterface::execDROP_FILEGROUP_CONF");
8252   m_impl->theWaiter.signal(NO_WAIT);
8253   DBUG_VOID_RETURN;
8254 }
8255 
8256 void
execDROP_FILEGROUP_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8257 NdbDictInterface::execDROP_FILEGROUP_REF(const NdbApiSignal * signal,
8258 					   const LinearSectionPtr ptr[3])
8259 {
8260   DBUG_ENTER("NdbDictInterface::execDROP_FILEGROUP_REF");
8261   const DropFilegroupRef* ref =
8262     CAST_CONSTPTR(DropFilegroupRef, signal->getDataPtr());
8263   m_error.code = ref->errorCode;
8264   DBUG_PRINT("info", ("Error code = %d", m_error.code));
8265   m_masterNodeId = ref->masterNodeId;
8266   m_impl->theWaiter.signal(NO_WAIT);
8267   DBUG_VOID_RETURN;
8268 }
8269 
8270 
8271 int
get_filegroup(NdbFilegroupImpl & dst,NdbDictionary::Object::Type type,const char * name)8272 NdbDictInterface::get_filegroup(NdbFilegroupImpl & dst,
8273 				NdbDictionary::Object::Type type,
8274 				const char * name){
8275   DBUG_ENTER("NdbDictInterface::get_filegroup");
8276   NdbApiSignal tSignal(m_reference);
8277   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
8278 
8279   Uint32 strLen = (Uint32)strlen(name) + 1;
8280 
8281   req->senderRef = m_reference;
8282   req->senderData = 0;
8283   req->requestType =
8284     GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
8285   req->tableNameLen = strLen;
8286   req->schemaTransId = m_tx.transId();
8287   tSignal.theReceiversBlockNumber = DBDICT;
8288   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
8289   tSignal.theLength = GetTabInfoReq::SignalLength;
8290 
8291   LinearSectionPtr ptr[1];
8292   ptr[0].p  = (Uint32*)name;
8293   ptr[0].sz = (strLen + 3)/4;
8294 
8295 #ifndef IGNORE_VALGRIND_WARNINGS
8296   if (strLen & 3)
8297   {
8298     Uint32 pad = 0;
8299     m_buffer.clear();
8300     m_buffer.append(name, strLen);
8301     m_buffer.append(&pad, 4);
8302     ptr[0].p = (Uint32*)m_buffer.get_data();
8303   }
8304 #endif
8305 
8306   int r = dictSignal(&tSignal, ptr, 1,
8307 		     -1, // any node
8308 		     WAIT_GET_TAB_INFO_REQ,
8309 		     DICT_WAITFOR_TIMEOUT, 100);
8310   if (r)
8311   {
8312     dst.m_id = RNIL;
8313     dst.m_version = ~0;
8314 
8315     DBUG_PRINT("info", ("get_filegroup failed dictSignal"));
8316     DBUG_RETURN(-1);
8317   }
8318 
8319   m_error.code = parseFilegroupInfo(dst,
8320 				    (Uint32*)m_buffer.get_data(),
8321 				    m_buffer.length() / 4);
8322 
8323   if(m_error.code)
8324   {
8325     DBUG_PRINT("info", ("get_filegroup failed parseFilegroupInfo %d",
8326                          m_error.code));
8327     DBUG_RETURN(m_error.code);
8328   }
8329 
8330   if(dst.m_type == NdbDictionary::Object::Tablespace)
8331   {
8332     NdbDictionary::LogfileGroup tmp;
8333     get_filegroup(NdbLogfileGroupImpl::getImpl(tmp),
8334 		  NdbDictionary::Object::LogfileGroup,
8335 		  dst.m_logfile_group_id);
8336     if (!dst.m_logfile_group_name.assign(tmp.getName()))
8337       DBUG_RETURN(m_error.code = 4000);
8338   }
8339 
8340   if(dst.m_type == type)
8341   {
8342     DBUG_RETURN(0);
8343   }
8344   DBUG_PRINT("info", ("get_filegroup failed no such filegroup"));
8345   DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
8346 }
8347 
8348 int
parseFilegroupInfo(NdbFilegroupImpl & dst,const Uint32 * data,Uint32 len)8349 NdbDictInterface::parseFilegroupInfo(NdbFilegroupImpl &dst,
8350 				     const Uint32 * data, Uint32 len)
8351 
8352 {
8353   SimplePropertiesLinearReader it(data, len);
8354 
8355   SimpleProperties::UnpackStatus status;
8356   DictFilegroupInfo::Filegroup fg; fg.init();
8357   status = SimpleProperties::unpack(it, &fg,
8358 				    DictFilegroupInfo::Mapping,
8359 				    DictFilegroupInfo::MappingSize,
8360 				    true, true);
8361 
8362   if(status != SimpleProperties::Eof){
8363     return CreateFilegroupRef::InvalidFormat;
8364   }
8365 
8366   dst.m_id = fg.FilegroupId;
8367   dst.m_version = fg.FilegroupVersion;
8368   dst.m_type = (NdbDictionary::Object::Type)fg.FilegroupType;
8369   dst.m_status = NdbDictionary::Object::Retrieved;
8370 
8371   if (!dst.m_name.assign(fg.FilegroupName))
8372     return 4000;
8373   dst.m_extent_size = fg.TS_ExtentSize;
8374   dst.m_undo_buffer_size = fg.LF_UndoBufferSize;
8375   dst.m_logfile_group_id = fg.TS_LogfileGroupId;
8376   dst.m_logfile_group_version = fg.TS_LogfileGroupVersion;
8377   dst.m_undo_free_words= ((Uint64)fg.LF_UndoFreeWordsHi << 32)
8378     | (fg.LF_UndoFreeWordsLo);
8379 
8380   return 0;
8381 }
8382 
8383 int
get_filegroup(NdbFilegroupImpl & dst,NdbDictionary::Object::Type type,Uint32 id)8384 NdbDictInterface::get_filegroup(NdbFilegroupImpl & dst,
8385 				NdbDictionary::Object::Type type,
8386 				Uint32 id){
8387   DBUG_ENTER("NdbDictInterface::get_filegroup");
8388   NdbApiSignal tSignal(m_reference);
8389   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
8390 
8391   req->senderRef = m_reference;
8392   req->senderData = 0;
8393   req->requestType =
8394     GetTabInfoReq::RequestById | GetTabInfoReq::LongSignalConf;
8395   req->tableId = id;
8396   req->schemaTransId = m_tx.transId();
8397   tSignal.theReceiversBlockNumber = DBDICT;
8398   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
8399   tSignal.theLength = GetTabInfoReq::SignalLength;
8400 
8401   int r = dictSignal(&tSignal, NULL, 1,
8402 		     -1, // any node
8403 		     WAIT_GET_TAB_INFO_REQ,
8404 		     DICT_WAITFOR_TIMEOUT, 100);
8405   if (r)
8406   {
8407     DBUG_PRINT("info", ("get_filegroup failed dictSignal"));
8408     DBUG_RETURN(-1);
8409   }
8410 
8411   m_error.code = parseFilegroupInfo(dst,
8412 				    (Uint32*)m_buffer.get_data(),
8413 				    m_buffer.length() / 4);
8414 
8415   if(m_error.code)
8416   {
8417     DBUG_PRINT("info", ("get_filegroup failed parseFilegroupInfo %d",
8418                          m_error.code));
8419     DBUG_RETURN(m_error.code);
8420   }
8421 
8422   if(dst.m_type == type)
8423   {
8424     DBUG_RETURN(0);
8425   }
8426   DBUG_PRINT("info", ("get_filegroup failed no such filegroup"));
8427   DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
8428 }
8429 
8430 int
get_file(NdbFileImpl & dst,NdbDictionary::Object::Type type,int node,const char * name)8431 NdbDictInterface::get_file(NdbFileImpl & dst,
8432 			   NdbDictionary::Object::Type type,
8433 			   int node,
8434 			   const char * name){
8435   DBUG_ENTER("NdbDictInterface::get_file");
8436   NdbApiSignal tSignal(m_reference);
8437   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
8438 
8439   Uint32 strLen = (Uint32)strlen(name) + 1;
8440 
8441   req->senderRef = m_reference;
8442   req->senderData = 0;
8443   req->requestType =
8444     GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
8445   req->tableNameLen = strLen;
8446   req->schemaTransId = m_tx.transId();
8447   tSignal.theReceiversBlockNumber = DBDICT;
8448   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
8449   tSignal.theLength = GetTabInfoReq::SignalLength;
8450 
8451   LinearSectionPtr ptr[1];
8452   ptr[0].p  = (Uint32*)name;
8453   ptr[0].sz = (strLen + 3)/4;
8454 
8455 #ifndef IGNORE_VALGRIND_WARNINGS
8456   if (strLen & 3)
8457   {
8458     Uint32 pad = 0;
8459     m_buffer.clear();
8460     m_buffer.append(name, strLen);
8461     m_buffer.append(&pad, 4);
8462     ptr[0].p = (Uint32*)m_buffer.get_data();
8463   }
8464 #endif
8465 
8466   int r = dictSignal(&tSignal, ptr, 1,
8467 		     node,
8468 		     WAIT_GET_TAB_INFO_REQ,
8469 		     DICT_WAITFOR_TIMEOUT, 100);
8470   if (r)
8471   {
8472     DBUG_PRINT("info", ("get_file failed dictSignal"));
8473     DBUG_RETURN(-1);
8474   }
8475 
8476   m_error.code = parseFileInfo(dst,
8477 			       (Uint32*)m_buffer.get_data(),
8478 			       m_buffer.length() / 4);
8479 
8480   if(m_error.code)
8481   {
8482     DBUG_PRINT("info", ("get_file failed parseFileInfo %d",
8483                          m_error.code));
8484     DBUG_RETURN(m_error.code);
8485   }
8486 
8487   if(dst.m_type == NdbDictionary::Object::Undofile)
8488   {
8489     NdbDictionary::LogfileGroup tmp;
8490     get_filegroup(NdbLogfileGroupImpl::getImpl(tmp),
8491 		  NdbDictionary::Object::LogfileGroup,
8492 		  dst.m_filegroup_id);
8493     if (!dst.m_filegroup_name.assign(tmp.getName()))
8494       DBUG_RETURN(m_error.code = 4000);
8495   }
8496   else if(dst.m_type == NdbDictionary::Object::Datafile)
8497   {
8498     NdbDictionary::Tablespace tmp;
8499     get_filegroup(NdbTablespaceImpl::getImpl(tmp),
8500 		  NdbDictionary::Object::Tablespace,
8501 		  dst.m_filegroup_id);
8502     if (!dst.m_filegroup_name.assign(tmp.getName()))
8503       DBUG_RETURN(m_error.code = 4000);
8504     dst.m_free *= tmp.getExtentSize();
8505   }
8506   else
8507     dst.m_filegroup_name.assign("Not Yet Implemented");
8508 
8509   if(dst.m_type == type)
8510   {
8511     DBUG_RETURN(0);
8512   }
8513   DBUG_PRINT("info", ("get_file failed no such file"));
8514   DBUG_RETURN(m_error.code = GetTabInfoRef::TableNotDefined);
8515 }
8516 
8517 int
parseFileInfo(NdbFileImpl & dst,const Uint32 * data,Uint32 len)8518 NdbDictInterface::parseFileInfo(NdbFileImpl &dst,
8519 				const Uint32 * data, Uint32 len)
8520 {
8521   SimplePropertiesLinearReader it(data, len);
8522 
8523   SimpleProperties::UnpackStatus status;
8524   DictFilegroupInfo::File f; f.init();
8525   status = SimpleProperties::unpack(it, &f,
8526 				    DictFilegroupInfo::FileMapping,
8527 				    DictFilegroupInfo::FileMappingSize,
8528 				    true, true);
8529 
8530   if(status != SimpleProperties::Eof){
8531     return CreateFilegroupRef::InvalidFormat;
8532   }
8533 
8534   dst.m_type= (NdbDictionary::Object::Type)f.FileType;
8535   dst.m_id= f.FileId;
8536   dst.m_version = f.FileVersion;
8537 
8538   dst.m_size= ((Uint64)f.FileSizeHi << 32) | (f.FileSizeLo);
8539   if (!dst.m_path.assign(f.FileName))
8540     return 4000;
8541 
8542   dst.m_filegroup_id= f.FilegroupId;
8543   dst.m_filegroup_version= f.FilegroupVersion;
8544   dst.m_free=  f.FileFreeExtents;
8545   return 0;
8546 }
8547 
8548 /**
8549  * HashMap
8550  */
8551 
NdbHashMapImpl()8552 NdbHashMapImpl::NdbHashMapImpl()
8553   : NdbDictionary::HashMap(* this),
8554     NdbDictObjectImpl(NdbDictionary::Object::HashMap), m_facade(this)
8555 {
8556 }
8557 
NdbHashMapImpl(NdbDictionary::HashMap & f)8558 NdbHashMapImpl::NdbHashMapImpl(NdbDictionary::HashMap & f)
8559   : NdbDictionary::HashMap(* this),
8560     NdbDictObjectImpl(NdbDictionary::Object::HashMap), m_facade(&f)
8561 {
8562 }
8563 
~NdbHashMapImpl()8564 NdbHashMapImpl::~NdbHashMapImpl()
8565 {
8566 }
8567 
8568 int
assign(const NdbHashMapImpl & org)8569 NdbHashMapImpl::assign(const NdbHashMapImpl& org)
8570 {
8571   m_id = org.m_id;
8572   m_version = org.m_version;
8573   m_status = org.m_status;
8574 
8575   m_name.assign(org.m_name);
8576   m_map.assign(org.m_map);
8577 
8578   return 0;
8579 }
8580 
8581 int
get_hashmap(NdbHashMapImpl & dst,const char * name)8582 NdbDictInterface::get_hashmap(NdbHashMapImpl & dst,
8583                               const char * name)
8584 {
8585   NdbApiSignal tSignal(m_reference);
8586   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
8587 
8588   Uint32 strLen = (Uint32)strlen(name) + 1;
8589 
8590   req->senderRef = m_reference;
8591   req->senderData = 0;
8592   req->requestType =
8593     GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
8594   req->tableNameLen = strLen;
8595   req->schemaTransId = m_tx.transId();
8596   tSignal.theReceiversBlockNumber = DBDICT;
8597   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
8598   tSignal.theLength = GetTabInfoReq::SignalLength;
8599 
8600   LinearSectionPtr ptr[1];
8601   ptr[0].p  = (Uint32*)name;
8602   ptr[0].sz = (strLen + 3)/4;
8603 
8604 #ifndef IGNORE_VALGRIND_WARNINGS
8605   if (strLen & 3)
8606   {
8607     Uint32 pad = 0;
8608     m_buffer.clear();
8609     m_buffer.append(name, strLen);
8610     m_buffer.append(&pad, 4);
8611     ptr[0].p = (Uint32*)m_buffer.get_data();
8612   }
8613 #endif
8614 
8615   int errCodes[] = {GetTabInfoRef::Busy, 0 };
8616   int r = dictSignal(&tSignal, ptr, 1,
8617 		     -1, // any node
8618 		     WAIT_GET_TAB_INFO_REQ,
8619 		     DICT_WAITFOR_TIMEOUT, 100, errCodes);
8620   if (r)
8621   {
8622     dst.m_id = -1;
8623     dst.m_version = ~0;
8624 
8625     return -1;
8626   }
8627 
8628   m_error.code = parseHashMapInfo(dst,
8629                                   (Uint32*)m_buffer.get_data(),
8630                                   m_buffer.length() / 4);
8631 
8632   return m_error.code;
8633 }
8634 
8635 int
get_hashmap(NdbHashMapImpl & dst,Uint32 id)8636 NdbDictInterface::get_hashmap(NdbHashMapImpl & dst,
8637                               Uint32 id)
8638 {
8639   NdbApiSignal tSignal(m_reference);
8640   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
8641 
8642   req->senderRef = m_reference;
8643   req->senderData = 0;
8644   req->requestType =
8645     GetTabInfoReq::RequestById | GetTabInfoReq::LongSignalConf;
8646   req->tableId = id;
8647   req->schemaTransId = m_tx.transId();
8648   tSignal.theReceiversBlockNumber = DBDICT;
8649   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
8650   tSignal.theLength = GetTabInfoReq::SignalLength;
8651 
8652   int errCodes[] = {GetTabInfoRef::Busy, 0 };
8653   int r = dictSignal(&tSignal, 0, 0,
8654 		     -1, // any node
8655 		     WAIT_GET_TAB_INFO_REQ,
8656 		     DICT_WAITFOR_TIMEOUT, 100, errCodes);
8657   if (r)
8658   {
8659     dst.m_id = -1;
8660     dst.m_version = ~0;
8661 
8662     return -1;
8663   }
8664 
8665   m_error.code = parseHashMapInfo(dst,
8666                                   (Uint32*)m_buffer.get_data(),
8667                                   m_buffer.length() / 4);
8668 
8669   return m_error.code;
8670 }
8671 
8672 int
parseHashMapInfo(NdbHashMapImpl & dst,const Uint32 * data,Uint32 len)8673 NdbDictInterface::parseHashMapInfo(NdbHashMapImpl &dst,
8674                                    const Uint32 * data, Uint32 len)
8675 {
8676   SimplePropertiesLinearReader it(data, len);
8677 
8678   SimpleProperties::UnpackStatus status;
8679   DictHashMapInfo::HashMap* hm = new DictHashMapInfo::HashMap();
8680   hm->init();
8681   status = SimpleProperties::unpack(it, hm,
8682                                     DictHashMapInfo::Mapping,
8683                                     DictHashMapInfo::MappingSize,
8684                                     true, true);
8685 
8686   if(status != SimpleProperties::Eof){
8687     delete hm;
8688     return CreateFilegroupRef::InvalidFormat;
8689   }
8690 
8691   dst.m_name.assign(hm->HashMapName);
8692   dst.m_id= hm->HashMapObjectId;
8693   dst.m_version = hm->HashMapVersion;
8694 
8695   /**
8696    * pack is stupid...and requires bytes!
8697    * we store shorts...so divide by 2
8698    */
8699   hm->HashMapBuckets /= sizeof(Uint16);
8700 
8701   dst.m_map.clear();
8702   for (Uint32 i = 0; i<hm->HashMapBuckets; i++)
8703   {
8704     dst.m_map.push_back(hm->HashMapValues[i]);
8705   }
8706 
8707   delete hm;
8708 
8709   return 0;
8710 }
8711 
8712 int
create_hashmap(const NdbHashMapImpl & src,NdbDictObjectImpl * obj,Uint32 flags)8713 NdbDictInterface::create_hashmap(const NdbHashMapImpl& src,
8714                                  NdbDictObjectImpl* obj,
8715                                  Uint32 flags)
8716 {
8717   {
8718     DictHashMapInfo::HashMap* hm = new DictHashMapInfo::HashMap();
8719     hm->init();
8720     BaseString::snprintf(hm->HashMapName, sizeof(hm->HashMapName),
8721                          "%s", src.getName());
8722     hm->HashMapBuckets = src.getMapLen();
8723     for (Uint32 i = 0; i<hm->HashMapBuckets; i++)
8724     {
8725       assert(NdbHashMapImpl::getImpl(src).m_map[i] <= NDB_PARTITION_MASK);
8726       hm->HashMapValues[i] = NdbHashMapImpl::getImpl(src).m_map[i];
8727     }
8728 
8729     /**
8730      * pack is stupid...and requires bytes!
8731      * we store shorts...so multiply by 2
8732      */
8733     hm->HashMapBuckets *= sizeof(Uint16);
8734     SimpleProperties::UnpackStatus s;
8735     UtilBufferWriter w(m_buffer);
8736     s = SimpleProperties::pack(w,
8737                                hm,
8738                                DictHashMapInfo::Mapping,
8739                                DictHashMapInfo::MappingSize, true);
8740 
8741     if(s != SimpleProperties::Eof)
8742     {
8743       abort();
8744     }
8745 
8746     delete hm;
8747   }
8748 
8749   NdbApiSignal tSignal(m_reference);
8750   tSignal.theReceiversBlockNumber = DBDICT;
8751   tSignal.theVerId_signalNumber = GSN_CREATE_HASH_MAP_REQ;
8752   tSignal.theLength = CreateHashMapReq::SignalLength;
8753 
8754   CreateHashMapReq* req = CAST_PTR(CreateHashMapReq, tSignal.getDataPtrSend());
8755   req->clientRef = m_reference;
8756   req->clientData = 0;
8757   req->requestInfo = flags;
8758   req->requestInfo |= m_tx.requestFlags();
8759   req->transId = m_tx.transId();
8760   req->transKey = m_tx.transKey();
8761   req->fragments = 0; // not used from here
8762   req->buckets = 0; // not used from here
8763 
8764   LinearSectionPtr ptr[3];
8765   ptr[0].p = (Uint32*)m_buffer.get_data();
8766   ptr[0].sz = m_buffer.length() / 4;
8767 
8768   int err[]= { CreateTableRef::Busy, CreateTableRef::NotMaster, 0 };
8769 
8770   /*
8771     Send signal without time-out since creating files can take a very long
8772     time if the file is very big.
8773   */
8774   Uint32 seccnt = 1;
8775   if (flags & CreateHashMapReq::CreateDefault)
8776   {
8777     seccnt = 0;
8778   }
8779   int ret = dictSignal(&tSignal, ptr, seccnt,
8780 		       0, // master
8781 		       WAIT_CREATE_INDX_REQ,
8782 		       -1, 100,
8783 		       err);
8784 
8785   if (ret == 0 && obj)
8786   {
8787     Uint32* data = (Uint32*)m_buffer.get_data();
8788     obj->m_id = data[0];
8789     obj->m_version = data[1];
8790   }
8791 
8792   return ret;
8793 }
8794 
8795 void
execCREATE_HASH_MAP_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8796 NdbDictInterface::execCREATE_HASH_MAP_REF(const NdbApiSignal * signal,
8797                                           const LinearSectionPtr ptr[3])
8798 {
8799   DBUG_ENTER("NdbDictInterface::execCREATE_HASH_MAP_REF");
8800   const CreateHashMapRef* ref =
8801     CAST_CONSTPTR(CreateHashMapRef, signal->getDataPtr());
8802   m_error.code = ref->errorCode;
8803   DBUG_PRINT("info", ("Error code = %d", m_error.code));
8804   m_masterNodeId = ref->masterNodeId;
8805   m_impl->theWaiter.signal(NO_WAIT);
8806   DBUG_VOID_RETURN;
8807 }
8808 
8809 
8810 void
execCREATE_HASH_MAP_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])8811 NdbDictInterface::execCREATE_HASH_MAP_CONF(const NdbApiSignal * signal,
8812                                            const LinearSectionPtr ptr[3])
8813 {
8814   DBUG_ENTER("NdbDictInterface::execCREATE_HASH_MAP_CONF");
8815   const CreateHashMapConf* conf=
8816     CAST_CONSTPTR(CreateHashMapConf, signal->getDataPtr());
8817   m_buffer.grow(4 * 2); // 2 words
8818   Uint32* data = (Uint32*)m_buffer.get_data();
8819   data[0] = conf->objectId;
8820   data[1] = conf->objectVersion;
8821 
8822   m_impl->theWaiter.signal(NO_WAIT);
8823   DBUG_VOID_RETURN;
8824 }
8825 
8826 /**
8827  * ForeignKey
8828  */
NdbForeignKeyImpl()8829 NdbForeignKeyImpl::NdbForeignKeyImpl()
8830   : NdbDictionary::ForeignKey(* this),
8831     NdbDictObjectImpl(NdbDictionary::Object::ForeignKey), m_facade(this)
8832 {
8833   init();
8834 }
8835 
NdbForeignKeyImpl(NdbDictionary::ForeignKey & f)8836 NdbForeignKeyImpl::NdbForeignKeyImpl(NdbDictionary::ForeignKey & f)
8837   : NdbDictionary::ForeignKey(* this),
8838     NdbDictObjectImpl(NdbDictionary::Object::ForeignKey), m_facade(&f)
8839 {
8840   init();
8841 }
8842 
~NdbForeignKeyImpl()8843 NdbForeignKeyImpl::~NdbForeignKeyImpl()
8844 {
8845 }
8846 
8847 void
init()8848 NdbForeignKeyImpl::init()
8849 {
8850   m_parent_columns.clear();
8851   m_child_columns.clear();
8852   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(m_references); i++)
8853   {
8854     m_references[i].m_objectId = RNIL;
8855     m_references[i].m_objectVersion = RNIL;
8856   }
8857   m_on_update_action = NoAction;
8858   m_on_delete_action = NoAction;
8859 }
8860 
8861 int
assign(const NdbForeignKeyImpl & org)8862 NdbForeignKeyImpl::assign(const NdbForeignKeyImpl& org)
8863 {
8864   m_id = org.m_id;
8865   m_version = org.m_version;
8866   m_status = org.m_status;
8867   m_type = org.m_type;
8868 
8869   if (!m_name.assign(org.m_name))
8870     return -1;
8871 
8872   for (Uint32 i = 0; i < NDB_ARRAY_SIZE(m_references); i++)
8873   {
8874     if (!m_references[i].m_name.assign(org.m_references[i].m_name))
8875       return -1;
8876 
8877     m_references[i].m_objectId = org.m_references[i].m_objectId;
8878     m_references[i].m_objectVersion = org.m_references[i].m_objectVersion;
8879   }
8880 
8881   m_parent_columns.clear();
8882   for (unsigned i = 0; i < org.m_parent_columns.size(); i++)
8883     m_parent_columns.push_back(org.m_parent_columns[i]);
8884 
8885   m_child_columns.clear();
8886   for (unsigned i = 0; i < org.m_child_columns.size(); i++)
8887     m_child_columns.push_back(org.m_child_columns[i]);
8888 
8889   m_on_update_action = org.m_impl.m_on_update_action;
8890   m_on_delete_action = org.m_impl.m_on_delete_action;
8891 
8892   return 0;
8893 }
8894 
8895 int
create_fk(const NdbForeignKeyImpl & src,NdbDictObjectImpl * obj,Uint32 flags)8896 NdbDictInterface::create_fk(const NdbForeignKeyImpl& src,
8897                             NdbDictObjectImpl* obj,
8898                             Uint32 flags)
8899 {
8900   DBUG_ENTER("NdbDictInterface::create_fk");
8901 
8902   DictForeignKeyInfo::ForeignKey fk; fk.init();
8903   BaseString::snprintf(fk.Name, sizeof(fk.Name),
8904                        "%s", src.getName());
8905 
8906   BaseString::snprintf(fk.ParentTableName, sizeof(fk.ParentTableName),
8907                        "%s", src.getParentTable());
8908 
8909   BaseString::snprintf(fk.ChildTableName, sizeof(fk.ChildTableName),
8910                        "%s", src.getChildTable());
8911 
8912   fk.ParentIndexName[0] = 0;
8913   if (src.getParentIndex())
8914   {
8915     BaseString::snprintf(fk.ParentIndexName, sizeof(fk.ParentIndexName),
8916                          "%s", src.getParentIndex());
8917   }
8918 
8919   fk.ChildIndexName[0] = 0;
8920   if (src.getChildIndex())
8921   {
8922     BaseString::snprintf(fk.ChildIndexName, sizeof(fk.ChildIndexName),
8923                          "%s", src.getChildIndex());
8924   }
8925   fk.ParentTableId = src.m_references[0].m_objectId;
8926   fk.ParentTableVersion = src.m_references[0].m_objectVersion;
8927   fk.ChildTableId = src.m_references[1].m_objectId;
8928   fk.ChildTableVersion = src.m_references[1].m_objectVersion;
8929   fk.ParentIndexId = src.m_references[2].m_objectId;
8930   fk.ParentIndexVersion = src.m_references[2].m_objectVersion;
8931   fk.ChildIndexId = src.m_references[3].m_objectId;
8932   fk.ChildIndexVersion = src.m_references[3].m_objectVersion;
8933   fk.OnUpdateAction = (Uint32)src.m_on_update_action;
8934   fk.OnDeleteAction = (Uint32)src.m_on_delete_action;
8935   for (unsigned i = 0; i < src.m_parent_columns.size(); i++)
8936     fk.ParentColumns[i] = src.m_parent_columns[i];
8937   fk.ParentColumnsLength = 4 * src.m_parent_columns.size(); // bytes :(
8938   for (unsigned i = 0; i < src.m_child_columns.size(); i++)
8939     fk.ChildColumns[i] = src.m_child_columns[i];
8940   fk.ChildColumnsLength = 4 * src.m_child_columns.size(); // bytes :(
8941 
8942 #ifndef NDEBUG
8943   {
8944     char buf[2048];
8945     ndbout_print(fk, buf, sizeof(buf));
8946     DBUG_PRINT("info", ("FK: %s", buf));
8947   }
8948 #endif
8949 
8950   {
8951     // don't allow slash in fk name
8952     if (strchr(fk.Name, '/') != 0)
8953     {
8954       m_error.code = 21090;
8955       DBUG_RETURN(-1);
8956     }
8957     // enforce format <parentid>/<childid>/name
8958     char buf[MAX_TAB_NAME_SIZE];
8959     BaseString::snprintf(buf, sizeof(buf), "%u/%u/%s",
8960                          fk.ParentTableId, fk.ChildTableId, fk.Name);
8961     strcpy(fk.Name, buf);
8962   }
8963 
8964   SimpleProperties::UnpackStatus s;
8965   UtilBufferWriter w(m_buffer);
8966   s = SimpleProperties::pack(w,
8967                              &fk,
8968                              DictForeignKeyInfo::Mapping,
8969                              DictForeignKeyInfo::MappingSize, true);
8970 
8971   if (s != SimpleProperties::Eof)
8972   {
8973     abort();
8974   }
8975 
8976   NdbApiSignal tSignal(m_reference);
8977   tSignal.theReceiversBlockNumber = DBDICT;
8978   tSignal.theVerId_signalNumber = GSN_CREATE_FK_REQ;
8979   tSignal.theLength = CreateFKReq::SignalLength;
8980 
8981   CreateFKReq* req = CAST_PTR(CreateFKReq, tSignal.getDataPtrSend());
8982   req->clientRef = m_reference;
8983   req->clientData = 0;
8984   req->requestInfo = flags;
8985   req->requestInfo |= m_tx.requestFlags();
8986   req->transId = m_tx.transId();
8987   req->transKey = m_tx.transKey();
8988 
8989   LinearSectionPtr ptr[3];
8990   ptr[0].p = (Uint32*)m_buffer.get_data();
8991   ptr[0].sz = m_buffer.length() / 4;
8992 
8993   int err[]= { CreateTableRef::Busy, CreateTableRef::NotMaster, 0 };
8994 
8995   /*
8996     Send signal without time-out since creating files can take a very long
8997     time if the file is very big.
8998   */
8999   Uint32 seccnt = 1;
9000   int ret = dictSignal(&tSignal, ptr, seccnt,
9001 		       0, // master
9002 		       WAIT_CREATE_INDX_REQ,
9003 		       -1, 100,
9004 		       err);
9005 
9006   if (ret == 0 && obj)
9007   {
9008     Uint32* data = (Uint32*)m_buffer.get_data();
9009     obj->m_id = data[0];
9010     obj->m_version = data[1];
9011   }
9012 
9013   DBUG_RETURN(ret);
9014 }
9015 
9016 void
execCREATE_FK_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9017 NdbDictInterface::execCREATE_FK_REF(const NdbApiSignal * signal,
9018                                           const LinearSectionPtr ptr[3])
9019 {
9020   DBUG_ENTER("NdbDictInterface::execCREATE_FK_REF");
9021   const CreateFKRef* ref = CAST_CONSTPTR(CreateFKRef, signal->getDataPtr());
9022   m_error.code = ref->errorCode;
9023   DBUG_PRINT("info", ("Error code = %d", m_error.code));
9024   m_masterNodeId = ref->masterNodeId;
9025   m_impl->theWaiter.signal(NO_WAIT);
9026   DBUG_VOID_RETURN;
9027 }
9028 
9029 void
execCREATE_FK_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9030 NdbDictInterface::execCREATE_FK_CONF(const NdbApiSignal * signal,
9031                                            const LinearSectionPtr ptr[3])
9032 {
9033   DBUG_ENTER("NdbDictInterface::execCREATE_FK_CONF");
9034   const CreateFKConf* conf= CAST_CONSTPTR(CreateFKConf, signal->getDataPtr());
9035   m_buffer.grow(4 * 2); // 2 words
9036   Uint32* data = (Uint32*)m_buffer.get_data();
9037   data[0] = conf->fkId;
9038   data[1] = conf->fkVersion;
9039 
9040   m_impl->theWaiter.signal(NO_WAIT);
9041   DBUG_VOID_RETURN;
9042 }
9043 
9044 int
get_fk(NdbForeignKeyImpl & dst,const char * name)9045 NdbDictInterface::get_fk(NdbForeignKeyImpl & dst,
9046                          const char * name)
9047 {
9048   DBUG_ENTER("NdbDictInterface::get_fk");
9049   NdbApiSignal tSignal(m_reference);
9050   GetTabInfoReq * req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend());
9051 
9052   Uint32 strLen = (Uint32)strlen(name) + 1;
9053 
9054   req->senderRef = m_reference;
9055   req->senderData = 0;
9056   req->requestType =
9057     GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf;
9058   req->tableNameLen = strLen;
9059   req->schemaTransId = m_tx.transId();
9060   tSignal.theReceiversBlockNumber = DBDICT;
9061   tSignal.theVerId_signalNumber   = GSN_GET_TABINFOREQ;
9062   tSignal.theLength = GetTabInfoReq::SignalLength;
9063 
9064   LinearSectionPtr ptr[1];
9065   ptr[0].p  = (Uint32*)name;
9066   ptr[0].sz = (strLen + 3)/4;
9067 
9068 #ifndef IGNORE_VALGRIND_WARNINGS
9069   if (strLen & 3)
9070   {
9071     Uint32 pad = 0;
9072     m_buffer.clear();
9073     m_buffer.append(name, strLen);
9074     m_buffer.append(&pad, 4);
9075     ptr[0].p = (Uint32*)m_buffer.get_data();
9076   }
9077 #endif
9078 
9079   int r = dictSignal(&tSignal, ptr, 1,
9080 		     -1, // any node
9081 		     WAIT_GET_TAB_INFO_REQ,
9082 		     DICT_WAITFOR_TIMEOUT, 100);
9083   if (r)
9084   {
9085     DBUG_PRINT("info", ("get_fk failed dictSignal"));
9086     DBUG_RETURN(-1);
9087   }
9088 
9089   m_error.code = parseForeignKeyInfo(dst,
9090                                      (Uint32*)m_buffer.get_data(),
9091                                      m_buffer.length() / 4);
9092 
9093   if (m_error.code)
9094   {
9095     DBUG_PRINT("info", ("get_fk failed parseFileInfo %d",
9096                          m_error.code));
9097     DBUG_RETURN(m_error.code);
9098   }
9099 
9100   DBUG_RETURN(0);
9101 }
9102 
9103 int
parseForeignKeyInfo(NdbForeignKeyImpl & dst,const Uint32 * data,Uint32 len)9104 NdbDictInterface::parseForeignKeyInfo(NdbForeignKeyImpl &dst,
9105                                       const Uint32 * data, Uint32 len)
9106 {
9107   SimplePropertiesLinearReader it(data, len);
9108 
9109   SimpleProperties::UnpackStatus status;
9110   DictForeignKeyInfo::ForeignKey fk; fk.init();
9111   status = SimpleProperties::unpack(it, &fk,
9112 				    DictForeignKeyInfo::Mapping,
9113 				    DictForeignKeyInfo::MappingSize,
9114 				    true, true);
9115 
9116   if(status != SimpleProperties::Eof)
9117   {
9118     return CreateFilegroupRef::InvalidFormat;
9119   }
9120 
9121   dst.m_id = fk.ForeignKeyId;
9122   dst.m_version = fk.ForeignKeyVersion;
9123   dst.m_type = NdbDictionary::Object::ForeignKey;
9124   dst.m_status = NdbDictionary::Object::Retrieved;
9125 
9126   if (!dst.m_name.assign(fk.Name))
9127     return 4000;
9128 
9129   dst.m_references[0].m_name.assign(fk.ParentTableName);
9130   dst.m_references[0].m_objectId = fk.ParentTableId;
9131   dst.m_references[0].m_objectVersion = fk.ParentTableVersion;
9132   dst.m_references[1].m_name.assign(fk.ChildTableName);
9133   dst.m_references[1].m_objectId = fk.ChildTableId;
9134   dst.m_references[1].m_objectVersion = fk.ChildTableVersion;
9135   if (fk.ParentIndexName[0] != 0)
9136   {
9137     dst.m_references[2].m_name.assign(fk.ParentIndexName);
9138   }
9139   dst.m_references[2].m_objectId = fk.ParentIndexId;
9140   dst.m_references[2].m_objectVersion = fk.ParentIndexVersion;
9141   if (fk.ChildIndexName[0] != 0)
9142   {
9143     dst.m_references[3].m_name.assign(fk.ChildIndexName);
9144   }
9145   dst.m_references[3].m_objectId = fk.ChildIndexId;
9146   dst.m_references[3].m_objectVersion = fk.ChildIndexVersion;
9147   dst.m_on_update_action =
9148     static_cast<NdbDictionary::ForeignKey::FkAction>(fk.OnUpdateAction);
9149   dst.m_on_delete_action =
9150     static_cast<NdbDictionary::ForeignKey::FkAction>(fk.OnDeleteAction);
9151 
9152   dst.m_parent_columns.clear();
9153   for (unsigned i = 0; i < fk.ParentColumnsLength / 4; i++)
9154     dst.m_parent_columns.push_back(fk.ParentColumns[i]);
9155 
9156   dst.m_child_columns.clear();
9157   for (unsigned i = 0; i < fk.ChildColumnsLength / 4; i++)
9158     dst.m_child_columns.push_back(fk.ChildColumns[i]);
9159 
9160   return 0;
9161 }
9162 
9163 int
drop_fk(const NdbDictObjectImpl & impl)9164 NdbDictInterface::drop_fk(const NdbDictObjectImpl & impl)
9165 {
9166   NdbApiSignal tSignal(m_reference);
9167   tSignal.theReceiversBlockNumber = DBDICT;
9168   tSignal.theVerId_signalNumber   = GSN_DROP_FK_REQ;
9169   tSignal.theLength = DropFKReq::SignalLength;
9170 
9171   DropFKReq * req = CAST_PTR(DropFKReq, tSignal.getDataPtrSend());
9172   req->clientRef = m_reference;
9173   req->clientData = 0;
9174   req->transId = m_tx.transId();
9175   req->transKey = m_tx.transKey();
9176   req->requestInfo = 0;
9177   req->requestInfo |= m_tx.requestFlags();
9178   req->fkId = impl.m_id;
9179   req->fkVersion = impl.m_version;
9180 
9181   int errCodes[] =
9182     { DropTableRef::NoDropTableRecordAvailable,
9183       DropTableRef::NotMaster,
9184       DropTableRef::Busy, 0 };
9185 
9186   return dictSignal(&tSignal, 0, 0,
9187                     0, // master
9188                     WAIT_DROP_TAB_REQ,
9189                     DICT_WAITFOR_TIMEOUT, 100,
9190                     errCodes);
9191 }
9192 
9193 void
execDROP_FK_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9194 NdbDictInterface::execDROP_FK_CONF(const NdbApiSignal * signal,
9195                                    const LinearSectionPtr ptr[3])
9196 {
9197   DBUG_ENTER("NdbDictInterface::execDROP_FK_CONF");
9198   //DropTableConf* const conf = CAST_CONSTPTR(DropTableConf, signal->getDataPtr());
9199 
9200   m_impl->theWaiter.signal(NO_WAIT);
9201   DBUG_VOID_RETURN;
9202 }
9203 
9204 void
execDROP_FK_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9205 NdbDictInterface::execDROP_FK_REF(const NdbApiSignal * signal,
9206                                   const LinearSectionPtr ptr[3])
9207 {
9208   DBUG_ENTER("NdbDictInterface::execDROP_FK_REF");
9209   const DropFKRef* ref = CAST_CONSTPTR(DropFKRef, signal->getDataPtr());
9210   m_error.code= ref->errorCode;
9211   DBUG_PRINT("info", ("Error code = %d", m_error.code));
9212   m_masterNodeId = ref->masterNodeId;
9213   m_impl->theWaiter.signal(NO_WAIT);
9214   DBUG_VOID_RETURN;
9215 }
9216 
9217 template class Vector<NdbTableImpl*>;
9218 template class Vector<NdbColumnImpl*>;
9219 
9220 int
beginSchemaTrans(bool retry711)9221 NdbDictionaryImpl::beginSchemaTrans(bool retry711)
9222 {
9223   DBUG_ENTER("beginSchemaTrans");
9224   if (m_tx.m_state == NdbDictInterface::Tx::Started) {
9225     m_error.code = 4410;
9226     DBUG_RETURN(-1);
9227   }
9228   if (!m_receiver.checkAllNodeVersionsMin(NDBD_SCHEMA_TRANS_VERSION))
9229   {
9230     /* Upgrade 6.3 -> 7.0 path */
9231     /* Schema transaction not possible until upgrade complete */
9232     m_error.code = 4411;
9233     DBUG_RETURN(-1);
9234   }
9235   // TODO real transId
9236   m_tx.m_transId = rand();
9237   if (m_tx.m_transId == 0)
9238     m_tx.m_transId = 1;
9239 
9240   m_tx.m_state = NdbDictInterface::Tx::NotStarted;
9241   m_tx.m_error.code = 0;
9242   m_tx.m_transKey = 0;
9243 
9244   int ret = m_receiver.beginSchemaTrans(retry711);
9245   if (ret == -1) {
9246     assert(m_tx.m_state == NdbDictInterface::Tx::NotStarted);
9247     DBUG_RETURN(-1);
9248   }
9249   DBUG_PRINT("info", ("transId: %x transKey: %x",
9250                       m_tx.m_transId, m_tx.m_transKey));
9251 
9252   assert(m_tx.m_state == NdbDictInterface::Tx::Started);
9253   assert(m_tx.m_error.code == 0);
9254   assert(m_tx.m_transKey != 0);
9255   DBUG_RETURN(0);
9256 }
9257 
9258 int
endSchemaTrans(Uint32 flags)9259 NdbDictionaryImpl::endSchemaTrans(Uint32 flags)
9260 {
9261   DBUG_ENTER("endSchemaTrans");
9262   if (m_tx.m_state == NdbDictInterface::Tx::NotStarted) {
9263     DBUG_RETURN(0);
9264   }
9265   /*
9266     Check if schema transaction has been aborted
9267     already, for example because of master node failure.
9268    */
9269   if (m_tx.m_state != NdbDictInterface::Tx::Started)
9270   {
9271     m_tx.m_op.clear();
9272     DBUG_PRINT("info", ("endSchemaTrans: state %u, flags 0x%x\n", m_tx.m_state, flags));
9273     if (m_tx.m_state == NdbDictInterface::Tx::Aborted && // rollback at master takeover
9274         flags & NdbDictionary::Dictionary::SchemaTransAbort)
9275     {
9276       m_tx.m_error.code = 0;
9277       DBUG_RETURN(0);
9278     }
9279     m_error.code = m_tx.m_error.code;
9280     DBUG_RETURN(-1);
9281   }
9282   DBUG_PRINT("info", ("transId: %x transKey: %x",
9283                       m_tx.m_transId, m_tx.m_transKey));
9284   int ret = m_receiver.endSchemaTrans(flags);
9285   if (ret == -1 || m_tx.m_error.code != 0) {
9286     DBUG_PRINT("info", ("endSchemaTrans: state %u, flags 0x%x\n", m_tx.m_state, flags));
9287     if (m_tx.m_state == NdbDictInterface::Tx::Committed && // rollforward at master takeover
9288         !(flags & NdbDictionary::Dictionary::SchemaTransAbort))
9289       goto committed;
9290     m_tx.m_op.clear();
9291     if (m_tx.m_state == NdbDictInterface::Tx::Aborted && // rollback at master takeover
9292         flags & NdbDictionary::Dictionary::SchemaTransAbort)
9293     {
9294       m_error.code = m_tx.m_error.code = 0;
9295       m_tx.m_state = NdbDictInterface::Tx::NotStarted;
9296       DBUG_RETURN(0);
9297     }
9298     if (m_tx.m_error.code != 0)
9299       m_error.code = m_tx.m_error.code;
9300     m_tx.m_state = NdbDictInterface::Tx::NotStarted;
9301     DBUG_RETURN(-1);
9302   }
9303 committed:
9304   // invalidate old version of altered table
9305   uint i;
9306   for (i = 0; i < m_tx.m_op.size(); i++) {
9307     NdbDictInterface::Tx::Op& op = m_tx.m_op[i];
9308     if (op.m_gsn == GSN_ALTER_TABLE_REQ)
9309     {
9310       op.m_impl->m_status = NdbDictionary::Object::Invalid;
9311       m_globalHash->lock();
9312       int ret = m_globalHash->dec_ref_count(op.m_impl);
9313       m_globalHash->unlock();
9314       if (ret != 0)
9315         abort();
9316     }
9317   }
9318   m_tx.m_state = NdbDictInterface::Tx::NotStarted;
9319   m_tx.m_op.clear();
9320   DBUG_RETURN(0);
9321 }
9322 
9323 int
getDefaultHashmapSize() const9324 NdbDictionaryImpl::getDefaultHashmapSize() const
9325 {
9326   return m_ndb.theImpl->get_ndbapi_config_parameters().m_default_hashmap_size;
9327 }
9328 
9329 bool
checkAllNodeVersionsMin(Uint32 minNdbVersion) const9330 NdbDictInterface::checkAllNodeVersionsMin(Uint32 minNdbVersion) const
9331 {
9332   for (Uint32 nodeId = 1; nodeId < MAX_NODES; nodeId++)
9333   {
9334     if (m_impl->getIsDbNode(nodeId) &&
9335         m_impl->getIsNodeSendable(nodeId) &&
9336         (m_impl->getNodeNdbVersion(nodeId) <
9337          minNdbVersion))
9338     {
9339       /* At least 1 sendable data node has lower-than-min
9340        * version
9341        */
9342       return false;
9343     }
9344   }
9345 
9346   return true;
9347 }
9348 
9349 
9350 int
beginSchemaTrans(bool retry711)9351 NdbDictInterface::beginSchemaTrans(bool retry711)
9352 {
9353   assert(m_tx.m_op.size() == 0);
9354   NdbApiSignal tSignal(m_reference);
9355   SchemaTransBeginReq* req =
9356     CAST_PTR(SchemaTransBeginReq, tSignal.getDataPtrSend());
9357 
9358   tSignal.theReceiversBlockNumber = DBDICT;
9359   tSignal.theVerId_signalNumber = GSN_SCHEMA_TRANS_BEGIN_REQ;
9360   tSignal.theLength = SchemaTransBeginReq::SignalLength;
9361 
9362   req->clientRef =  m_reference;
9363   req->transId = m_tx.m_transId;
9364   req->requestInfo = 0;
9365 
9366   int errCodes[] = {
9367     SchemaTransBeginRef::NotMaster,
9368     SchemaTransBeginRef::Busy,
9369     retry711 ? SchemaTransBeginRef::BusyWithNR : 0,
9370     0
9371   };
9372 
9373   int ret = dictSignal(
9374       &tSignal,
9375       0,
9376       0,
9377       0,
9378       WAIT_SCHEMA_TRANS,
9379       DICT_WAITFOR_TIMEOUT,
9380       100,
9381       errCodes);
9382   if (ret == -1)
9383     return -1;
9384   return 0;
9385 }
9386 
9387 int
endSchemaTrans(Uint32 flags)9388 NdbDictInterface::endSchemaTrans(Uint32 flags)
9389 {
9390   NdbApiSignal tSignal(m_reference);
9391   SchemaTransEndReq* req =
9392     CAST_PTR(SchemaTransEndReq, tSignal.getDataPtrSend());
9393 
9394   tSignal.theReceiversBlockNumber = DBDICT;
9395   tSignal.theVerId_signalNumber = GSN_SCHEMA_TRANS_END_REQ;
9396   tSignal.theLength = SchemaTransEndReq::SignalLength;
9397 
9398   req->clientRef =  m_reference;
9399   req->transId = m_tx.m_transId;
9400   req->requestInfo = 0;
9401   req->transKey = m_tx.m_transKey;
9402   req->flags = flags;
9403 
9404   int errCodes[] = {
9405     SchemaTransEndRef::NotMaster,
9406     0
9407   };
9408   int ret = dictSignal(
9409       &tSignal,
9410       0,
9411       0,
9412       0,
9413       WAIT_SCHEMA_TRANS,
9414       DICT_WAITFOR_TIMEOUT,
9415       100,
9416       errCodes);
9417   if (ret == -1)
9418     return -1;
9419   return 0;
9420 }
9421 
9422 void
execSCHEMA_TRANS_BEGIN_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9423 NdbDictInterface::execSCHEMA_TRANS_BEGIN_CONF(const NdbApiSignal * signal,
9424                                               const LinearSectionPtr ptr[3])
9425 {
9426   DBUG_ENTER("NdbDictInterface::execSCHEMA_TRANS_BEGIN_CONF");
9427   const SchemaTransBeginConf* conf=
9428     CAST_CONSTPTR(SchemaTransBeginConf, signal->getDataPtr());
9429   assert(m_tx.m_transId == conf->transId);
9430   assert(m_tx.m_state == Tx::NotStarted);
9431   m_tx.m_state = Tx::Started;
9432   m_tx.m_transKey = conf->transKey;
9433   m_impl->theWaiter.signal(NO_WAIT);
9434   DBUG_VOID_RETURN;
9435 }
9436 
9437 void
execSCHEMA_TRANS_BEGIN_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9438 NdbDictInterface::execSCHEMA_TRANS_BEGIN_REF(const NdbApiSignal * signal,
9439                                              const LinearSectionPtr ptr[3])
9440 {
9441   DBUG_ENTER("NdbDictInterface::execSCHEMA_TRANS_BEGIN_REF");
9442   const SchemaTransBeginRef* ref =
9443     CAST_CONSTPTR(SchemaTransBeginRef, signal->getDataPtr());
9444   m_error.code = ref->errorCode;
9445   DBUG_PRINT("info", ("Error code = %d", m_error.code));
9446   m_masterNodeId = ref->masterNodeId;
9447   m_impl->theWaiter.signal(NO_WAIT);
9448   DBUG_VOID_RETURN;
9449 }
9450 
9451 void
execSCHEMA_TRANS_END_CONF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9452 NdbDictInterface::execSCHEMA_TRANS_END_CONF(const NdbApiSignal * signal,
9453                                             const LinearSectionPtr ptr[3])
9454 {
9455   DBUG_ENTER("NdbDictInterface::execSCHEMA_TRANS_END_CONF");
9456 #ifndef NDEBUG
9457   const SchemaTransEndConf* conf=
9458     CAST_CONSTPTR(SchemaTransEndConf, signal->getDataPtr());
9459   assert(m_tx.m_transId == conf->transId);
9460 #endif
9461   m_impl->theWaiter.signal(NO_WAIT);
9462   DBUG_VOID_RETURN;
9463 }
9464 
9465 void
execSCHEMA_TRANS_END_REF(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9466 NdbDictInterface::execSCHEMA_TRANS_END_REF(const NdbApiSignal * signal,
9467                                            const LinearSectionPtr ptr[3])
9468 {
9469   DBUG_ENTER("NdbDictInterface::execSCHEMA_TRANS_END_REF");
9470   const SchemaTransEndRef* ref =
9471     CAST_CONSTPTR(SchemaTransEndRef, signal->getDataPtr());
9472   m_error.code = ref->errorCode;
9473   DBUG_PRINT("info", ("Error code = %d", m_error.code));
9474   m_tx.m_error.code = ref->errorCode;
9475   m_masterNodeId = ref->masterNodeId;
9476   m_impl->theWaiter.signal(NO_WAIT);
9477   DBUG_VOID_RETURN;
9478 }
9479 
9480 void
execSCHEMA_TRANS_END_REP(const NdbApiSignal * signal,const LinearSectionPtr ptr[3])9481 NdbDictInterface::execSCHEMA_TRANS_END_REP(const NdbApiSignal * signal,
9482                                            const LinearSectionPtr ptr[3])
9483 {
9484   DBUG_ENTER("NdbDictInterface::SCHEMA_TRANS_END_REP");
9485   const SchemaTransEndRep* rep =
9486     CAST_CONSTPTR(SchemaTransEndRep, signal->getDataPtr());
9487 
9488   if (m_tx.m_state != Tx::Started)
9489   {
9490     // Ignore TRANS_END_REP if Txn was never started
9491     DBUG_VOID_RETURN;
9492   }
9493 
9494   (rep->errorCode == 0) ?
9495     m_tx.m_state = Tx::Committed
9496     :
9497     m_tx.m_state = Tx::Aborted;
9498   m_tx.m_error.code = rep->errorCode;
9499   m_masterNodeId = rep->masterNodeId;
9500   m_impl->theWaiter.signal(NO_WAIT);
9501   DBUG_VOID_RETURN;
9502 }
9503 
9504 const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT = 0;
9505 const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_FIXED_MEMORY = 0;
9506 const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY = 0;
9507 const NdbDictionary::Column * NdbDictionary::Column::ROW_COUNT = 0;
9508 const NdbDictionary::Column * NdbDictionary::Column::COMMIT_COUNT = 0;
9509 const NdbDictionary::Column * NdbDictionary::Column::ROW_SIZE = 0;
9510 const NdbDictionary::Column * NdbDictionary::Column::RANGE_NO = 0;
9511 const NdbDictionary::Column * NdbDictionary::Column::DISK_REF = 0;
9512 const NdbDictionary::Column * NdbDictionary::Column::RECORDS_IN_RANGE = 0;
9513 const NdbDictionary::Column * NdbDictionary::Column::ROWID = 0;
9514 const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI = 0;
9515 const NdbDictionary::Column * NdbDictionary::Column::ROW_GCI64 = 0;
9516 const NdbDictionary::Column * NdbDictionary::Column::ROW_AUTHOR = 0;
9517 const NdbDictionary::Column * NdbDictionary::Column::ANY_VALUE = 0;
9518 const NdbDictionary::Column * NdbDictionary::Column::COPY_ROWID = 0;
9519 const NdbDictionary::Column * NdbDictionary::Column::OPTIMIZE = 0;
9520 const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_EXTENT_SPACE = 0;
9521 const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE = 0;
9522 const NdbDictionary::Column * NdbDictionary::Column::LOCK_REF = 0;
9523 const NdbDictionary::Column * NdbDictionary::Column::OP_ID = 0;
9524 
9525 template class Vector<NdbDictInterface::Tx::Op>;
9526