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, <req, 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