1 /*
2    Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
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 <signaldata/DictTabInfo.hpp>
26 #include <ndb_limits.h>
27 #include <NdbOut.hpp>
28 
29 //static
30 const
31 SimpleProperties::SP2StructMapping
32 DictTabInfo::TableMapping[] = {
33   DTIMAPS(Table, TableName, TableName, 0, MAX_TAB_NAME_SIZE),
34   DTIMAP(Table, TableId, TableId),
35   DTIMAPS(Table, PrimaryTable, PrimaryTable, 0, MAX_TAB_NAME_SIZE),
36   DTIMAP(Table, PrimaryTableId, PrimaryTableId),
37   DTIMAP2(Table, TableLoggedFlag, TableLoggedFlag, 0, 1),
38   DTIMAP2(Table, TableTemporaryFlag, TableTemporaryFlag, 0, 1),
39   DTIMAP2(Table, ForceVarPartFlag, ForceVarPartFlag, 0, 1),
40   DTIMAP2(Table, TableKValue, TableKValue,         6, 6),
41   DTIMAP2(Table, MinLoadFactor, MinLoadFactor,     0, 90),
42   DTIMAP2(Table, MaxLoadFactor, MaxLoadFactor,    25, 110),
43   DTIMAP2(Table, FragmentTypeVal, FragmentType,       0, 3),
44   DTIMAP2(Table, TableTypeVal, TableType,         1, 3),
45   DTIMAP(Table, NoOfKeyAttr, NoOfKeyAttr),
46   DTIMAP2(Table, NoOfAttributes, NoOfAttributes, 1, MAX_ATTRIBUTES_IN_TABLE),
47   DTIMAP(Table, NoOfNullable, NoOfNullable),
48   DTIMAP2(Table, NoOfVariable, NoOfVariable,       0, 0),
49   DTIMAP(Table, KeyLength, KeyLength),
50   DTIMAP(Table, TableVersion, TableVersion),
51   DTIMAP(Table, IndexState, IndexState),
52   DTIMAP(Table, InsertTriggerId, InsertTriggerId),
53   DTIMAP(Table, UpdateTriggerId, UpdateTriggerId),
54   DTIMAP(Table, DeleteTriggerId, DeleteTriggerId),
55   DTIMAP(Table, CustomTriggerId, CustomTriggerId),
56   DTIMAP2(Table, FrmLen, FrmLen, 0, MAX_FRM_DATA_SIZE),
57   DTIMAPB(Table, FrmData, FrmData, 0, MAX_FRM_DATA_SIZE, FrmLen),
58   DTIMAP2(Table, FragmentCount, FragmentCount, 0, MAX_NDB_PARTITIONS),
59   DTIMAP2(Table, ReplicaDataLen, ReplicaDataLen, 0, MAX_FRAGMENT_DATA_BYTES),
60   DTIMAPB(Table, ReplicaData, ReplicaData, 0, MAX_FRAGMENT_DATA_BYTES, ReplicaDataLen),
61   DTIMAP2(Table, FragmentDataLen, FragmentDataLen, 0, 6*MAX_NDB_PARTITIONS),
62   DTIMAPB(Table, FragmentData, FragmentData, 0, 6*MAX_NDB_PARTITIONS, FragmentDataLen),
63   DTIMAP2(Table, TablespaceDataLen, TablespaceDataLen, 0, 8*MAX_NDB_PARTITIONS),
64   DTIMAPB(Table, TablespaceData, TablespaceData, 0, 8*MAX_NDB_PARTITIONS, TablespaceDataLen),
65   DTIMAP2(Table, RangeListDataLen, RangeListDataLen, 0, 8*MAX_NDB_PARTITIONS),
66   DTIMAPB(Table, RangeListData, RangeListData, 0, 8*MAX_NDB_PARTITIONS, RangeListDataLen),
67   DTIMAP(Table, TablespaceId, TablespaceId),
68   DTIMAP(Table, TablespaceVersion, TablespaceVersion),
69   DTIMAP(Table, MaxRowsLow, MaxRowsLow),
70   DTIMAP(Table, MaxRowsHigh, MaxRowsHigh),
71   DTIMAP(Table, DefaultNoPartFlag, DefaultNoPartFlag),
72   DTIMAP(Table, LinearHashFlag, LinearHashFlag),
73   DTIMAP(Table, TablespaceVersion, TablespaceVersion),
74   DTIMAP(Table, RowGCIFlag, RowGCIFlag),
75   DTIMAP(Table, RowChecksumFlag, RowChecksumFlag),
76   DTIMAP(Table, MaxRowsLow, MaxRowsLow),
77   DTIMAP(Table, MaxRowsHigh, MaxRowsHigh),
78   DTIMAP(Table, MinRowsLow, MinRowsLow),
79   DTIMAP(Table, MinRowsHigh, MinRowsHigh),
80   DTIMAP(Table, SingleUserMode, SingleUserMode),
81   DTIMAP(Table, HashMapObjectId, HashMapObjectId),
82   DTIMAP(Table, HashMapVersion, HashMapVersion),
83   DTIMAP(Table, TableStorageType, TableStorageType),
84   DTIMAP(Table, ExtraRowGCIBits, ExtraRowGCIBits),
85   DTIMAP(Table, ExtraRowAuthorBits, ExtraRowAuthorBits),
86   DTIBREAK(AttributeName)
87 };
88 
89 //static
90 const Uint32 DictTabInfo::TableMappingSize =
91 sizeof(DictTabInfo::TableMapping) / sizeof(SimpleProperties::SP2StructMapping);
92 
93 //static
94 const
95 SimpleProperties::SP2StructMapping
96 DictTabInfo::AttributeMapping[] = {
97   DTIMAPS(Attribute, AttributeName, AttributeName, 0, MAX_ATTR_NAME_SIZE),
98   DTIMAP(Attribute, AttributeId, AttributeId),
99   DTIMAP(Attribute, AttributeType, AttributeType),
100   DTIMAP2(Attribute, AttributeSize, AttributeSize,     3, 7),
101   DTIMAP2(Attribute, AttributeArraySize, AttributeArraySize, 0, 65535),
102   DTIMAP2(Attribute, AttributeArrayType, AttributeArrayType, 0, 3),
103   DTIMAP2(Attribute, AttributeKeyFlag, AttributeKeyFlag, 0, 1),
104   DTIMAP2(Attribute, AttributeNullableFlag, AttributeNullableFlag, 0, 1),
105   DTIMAP2(Attribute, AttributeDKey, AttributeDKey, 0, 1),
106   DTIMAP2(Attribute, AttributeStorageType, AttributeStorageType, 0, 1),
107   DTIMAP2(Attribute, AttributeDynamic, AttributeDynamic, 0, 1),
108   DTIMAP(Attribute, AttributeExtType, AttributeExtType),
109   DTIMAP(Attribute, AttributeExtPrecision, AttributeExtPrecision),
110   DTIMAP(Attribute, AttributeExtScale, AttributeExtScale),
111   DTIMAP(Attribute, AttributeExtLength, AttributeExtLength),
112   DTIMAP2(Attribute, AttributeAutoIncrement, AttributeAutoIncrement, 0, 1),
113 
114   DTIMAP2(Attribute, AttributeDefaultValueLen, AttributeDefaultValueLen,
115           0, MAX_ATTR_DEFAULT_VALUE_SIZE),
116   DTIMAPB(Attribute, AttributeDefaultValue, AttributeDefaultValue,
117     0, MAX_ATTR_DEFAULT_VALUE_SIZE, AttributeDefaultValueLen),
118 
119   DTIBREAK(AttributeEnd)
120 };
121 
122 //static
123 const Uint32 DictTabInfo::AttributeMappingSize =
124 sizeof(DictTabInfo::AttributeMapping) /
125 sizeof(SimpleProperties::SP2StructMapping);
126 
printDICTTABINFO(FILE * output,const Uint32 * theData,Uint32 len,Uint16 receiverBlockNo)127 bool printDICTTABINFO(FILE * output, const Uint32 * theData,
128 		      Uint32 len, Uint16 receiverBlockNo)
129 {
130 //  const DictTabInfo * const sig = (DictTabInfo *) theData;
131 
132   fprintf(output, "Signal data: ");
133   Uint32 i = 0;
134   while (i < len)
135     fprintf(output, "H\'%.8x ", theData[i++]);
136   fprintf(output,"\n");
137   return true;
138 }
139 
140 void
init()141 DictTabInfo::Table::init(){
142   memset(TableName, 0, sizeof(TableName));//TableName[0] = 0;
143   TableId = ~0;
144   memset(PrimaryTable, 0, sizeof(PrimaryTable));//PrimaryTable[0] = 0; // Only used when "index"
145   PrimaryTableId = RNIL;
146   TableLoggedFlag = 1;
147   TableTemporaryFlag = 0;
148   ForceVarPartFlag = 0;
149   NoOfKeyAttr = 0;
150   NoOfAttributes = 0;
151   NoOfNullable = 0;
152   NoOfVariable = 0;
153   TableKValue = 6;
154   MinLoadFactor = 78;
155   MaxLoadFactor = 80;
156   KeyLength = 0;
157   FragmentType = DictTabInfo::HashMapPartition;
158   TableType = DictTabInfo::UndefTableType;
159   TableVersion = 0;
160   IndexState = ~0;
161   InsertTriggerId = RNIL;
162   UpdateTriggerId = RNIL;
163   DeleteTriggerId = RNIL;
164   CustomTriggerId = RNIL;
165   FrmLen = 0;
166   FragmentDataLen = 0;
167   ReplicaDataLen = 0;
168   RangeListDataLen = 0;
169   TablespaceDataLen = 0;
170   memset(FrmData, 0, sizeof(FrmData));
171   memset(FragmentData, 0, sizeof(FragmentData));
172   memset(ReplicaData, 0, sizeof(ReplicaData));
173   memset(RangeListData, 0, sizeof(RangeListData));
174   memset(TablespaceData, 0, sizeof(TablespaceData));
175   FragmentCount = 0;
176   TablespaceId = RNIL;
177   TablespaceVersion = ~0;
178   MaxRowsLow = 0;
179   MaxRowsHigh = 0;
180   DefaultNoPartFlag = 1;
181   LinearHashFlag = 1;
182 
183   RowGCIFlag = ~0;
184   RowChecksumFlag = ~0;
185 
186   MaxRowsLow = 0;
187   MaxRowsHigh = 0;
188   MinRowsLow = 0;
189   MinRowsHigh = 0;
190 
191   SingleUserMode = 0;
192 
193   HashMapObjectId = RNIL;
194   HashMapVersion = RNIL;
195 
196   TableStorageType = NDB_STORAGETYPE_DEFAULT;
197 
198   ExtraRowGCIBits = 0;
199   ExtraRowAuthorBits = 0;
200 }
201 
202 void
init()203 DictTabInfo::Attribute::init(){
204   memset(AttributeName, 0, sizeof(AttributeName));//AttributeName[0] = 0;
205   AttributeId = 0xFFFF; // ZNIL
206   AttributeType = ~0, // deprecated
207   AttributeSize = DictTabInfo::a32Bit;
208   AttributeArraySize = 1;
209   AttributeArrayType = NDB_ARRAYTYPE_FIXED;
210   AttributeKeyFlag = 0;
211   AttributeNullableFlag = 0;
212   AttributeDKey = 0;
213   AttributeExtType = DictTabInfo::ExtUnsigned,
214   AttributeExtPrecision = 0,
215   AttributeExtScale = 0,
216   AttributeExtLength = 0,
217   AttributeAutoIncrement = false;
218   AttributeStorageType = 0;
219   AttributeDynamic = 0;                         // Default is not dynamic
220   AttributeDefaultValueLen = 0;                 //Default byte sizes of binary default value is 0
221   memset(AttributeDefaultValue, 0, sizeof(AttributeDefaultValue));
222 }
223 
224 //static
225 const
226 SimpleProperties::SP2StructMapping
227 DictFilegroupInfo::Mapping[] = {
228   DFGIMAPS(Filegroup, FilegroupName, FilegroupName, 0, MAX_TAB_NAME_SIZE),
229   DFGIMAP2(Filegroup, FilegroupType, FilegroupType, 0, 1),
230   DFGIMAP(Filegroup,  FilegroupId, FilegroupId),
231   DFGIMAP(Filegroup,  FilegroupVersion, FilegroupVersion),
232 
233   DFGIMAP(Filegroup,  TS_ExtentSize,   TS_ExtentSize),
234   DFGIMAP(Filegroup,  TS_LogfileGroupId, TS_LogfileGroupId),
235   DFGIMAP(Filegroup,  TS_LogfileGroupVersion, TS_LogfileGroupVersion),
236   DFGIMAP(Filegroup,  TS_GrowLimit, TS_DataGrow.GrowLimit),
237   DFGIMAP(Filegroup,  TS_GrowSizeHi, TS_DataGrow.GrowSizeHi),
238   DFGIMAP(Filegroup,  TS_GrowSizeLo, TS_DataGrow.GrowSizeLo),
239   DFGIMAPS(Filegroup, TS_GrowPattern, TS_DataGrow.GrowPattern, 0, PATH_MAX),
240   DFGIMAP(Filegroup,  TS_GrowMaxSize, TS_DataGrow.GrowMaxSize),
241 
242   DFGIMAP(Filegroup,  LF_UndoBufferSize, LF_UndoBufferSize),
243   DFGIMAP(Filegroup,  LF_UndoGrowLimit, LF_UndoGrow.GrowLimit),
244   DFGIMAP(Filegroup,  LF_UndoGrowSizeHi, LF_UndoGrow.GrowSizeHi),
245   DFGIMAP(Filegroup,  LF_UndoGrowSizeLo, LF_UndoGrow.GrowSizeLo),
246   DFGIMAPS(Filegroup, LF_UndoGrowPattern, LF_UndoGrow.GrowPattern, 0,PATH_MAX),
247   DFGIMAP(Filegroup,  LF_UndoGrowMaxSize, LF_UndoGrow.GrowMaxSize),
248   DFGIMAP(Filegroup,  LF_UndoFreeWordsHi, LF_UndoFreeWordsHi),
249   DFGIMAP(Filegroup,  LF_UndoFreeWordsLo, LF_UndoFreeWordsLo),
250 
251   DFGIBREAK(FileName)
252 };
253 
254 //static
255 const Uint32 DictFilegroupInfo::MappingSize =
256 sizeof(DictFilegroupInfo::Mapping) / sizeof(SimpleProperties::SP2StructMapping);
257 
258 //static
259 const
260 SimpleProperties::SP2StructMapping
261 DictFilegroupInfo::FileMapping[] = {
262   DFGIMAPS(File, FileName, FileName, 0, PATH_MAX),
263   DFGIMAP2(File, FileType, FileType, 0, 1),
264   DFGIMAP(File, FileId, FileId),
265   DFGIMAP(File, FileVersion, FileVersion),
266   DFGIMAP(File, FileFGroupId, FilegroupId),
267   DFGIMAP(File, FileFGroupVersion, FilegroupVersion),
268   DFGIMAP(File, FileSizeHi, FileSizeHi),
269   DFGIMAP(File, FileSizeLo, FileSizeLo),
270   DFGIMAP(File, FileFreeExtents, FileFreeExtents),
271   DFGIBREAK(FileEnd)
272 };
273 
274 //static
275 const Uint32 DictFilegroupInfo::FileMappingSize =
276 sizeof(DictFilegroupInfo::FileMapping) /
277 sizeof(SimpleProperties::SP2StructMapping);
278 
279 void
init()280 DictFilegroupInfo::Filegroup::init(){
281   memset(FilegroupName, 0, sizeof(FilegroupName));
282   FilegroupType = ~0;
283   FilegroupId = ~0;
284   FilegroupVersion = ~0;
285 
286   TS_ExtentSize = 0;
287   TS_LogfileGroupId = ~0;
288   TS_LogfileGroupVersion = ~0;
289   TS_DataGrow.GrowLimit = 0;
290   TS_DataGrow.GrowSizeHi = 0;
291   TS_DataGrow.GrowSizeLo = 0;
292   memset(TS_DataGrow.GrowPattern, 0, sizeof(TS_DataGrow.GrowPattern));
293   TS_DataGrow.GrowMaxSize = 0;
294   LF_UndoFreeWordsHi= 0;
295   LF_UndoFreeWordsLo= 0;
296 }
297 
298 void
init()299 DictFilegroupInfo::File::init(){
300   memset(FileName, 0, sizeof(FileName));
301   FileType = ~0;
302   FileId = ~0;
303   FileVersion = ~0;
304   FilegroupId = ~0;
305   FilegroupVersion = ~0;
306   FileSizeHi = 0;
307   FileSizeLo = 0;
308   FileFreeExtents = 0;
309 }
310 
311 // blob table name hack
312 
313 bool
isBlobTableName(const char * name,Uint32 * ptab_id,Uint32 * pcol_no)314 DictTabInfo::isBlobTableName(const char* name, Uint32* ptab_id, Uint32* pcol_no)
315 {
316   const char* const prefix = "NDB$BLOB_";
317   const char* s = strrchr(name, table_name_separator);
318   s = (s == NULL ? name : s + 1);
319   if (strncmp(s, prefix, strlen(prefix)) != 0)
320     return false;
321   s += strlen(prefix);
322   uint i, n;
323   for (i = 0, n = 0; '0' <= s[i] && s[i] <= '9'; i++)
324     n = 10 * n + (s[i] - '0');
325   if (i == 0 || s[i] != '_')
326     return false;
327   const uint tab_id = n;
328   s = &s[i + 1];
329   for (i = 0, n = 0; '0' <= s[i] && s[i] <= '9'; i++)
330     n = 10 * n + (s[i] - '0');
331   if (i == 0 || s[i] != 0)
332     return false;
333   const uint col_no = n;
334   if (ptab_id)
335     *ptab_id = tab_id;
336   if (pcol_no)
337     *pcol_no = col_no;
338   return true;
339 }
340 
341 /**
342  * HashMap
343  */
344 const
345 SimpleProperties::SP2StructMapping
346 DictHashMapInfo::Mapping[] = {
347   DHMIMAPS(HashMap, HashMapName, HashMapName, 0, MAX_TAB_NAME_SIZE),
348   DHMIMAP2(HashMap, HashMapBuckets, HashMapBuckets, 0, NDB_MAX_HASHMAP_BUCKETS),
349   DTIMAP(HashMap, HashMapObjectId, HashMapObjectId),
350   DTIMAP(HashMap, HashMapVersion, HashMapVersion),
351 
352   /**
353    * This *should* change to Uint16 or similar once endian is pushed
354    */
355   DHMIMAPB(HashMap, HashMapValues, HashMapValues, 0,
356            NDB_MAX_HASHMAP_BUCKETS * sizeof(Uint16), HashMapBuckets)
357 };
358 
359 //static
360 const Uint32 DictHashMapInfo::MappingSize =
361   sizeof(DictHashMapInfo::Mapping) / sizeof(SimpleProperties::SP2StructMapping);
362 
363 
364 void
init()365 DictHashMapInfo::HashMap::init()
366 {
367   bzero(this, sizeof(* this));
368 }
369 
370 /**
371  * ForeignKey
372  */
373 const
374 SimpleProperties::SP2StructMapping
375 DictForeignKeyInfo::Mapping[] = {
376   DFKIMAPS(ForeignKey, ForeignKeyName, Name, 0, MAX_TAB_NAME_SIZE),
377   DFKIMAPS(ForeignKey, ForeignKeyParentTableName, ParentTableName,
378            0, MAX_TAB_NAME_SIZE),
379   DFKIMAPS(ForeignKey, ForeignKeyParentIndexName, ParentIndexName,
380            0, MAX_TAB_NAME_SIZE),
381   DFKIMAPS(ForeignKey, ForeignKeyChildTableName, ChildTableName,
382            0, MAX_TAB_NAME_SIZE),
383   DFKIMAPS(ForeignKey, ForeignKeyChildIndexName, ChildIndexName,
384            0, MAX_TAB_NAME_SIZE),
385   DFKIMAP(ForeignKey, ForeignKeyId, ForeignKeyId),
386   DFKIMAP(ForeignKey, ForeignKeyVersion, ForeignKeyVersion),
387   DFKIMAP(ForeignKey, ForeignKeyParentTableId, ParentTableId),
388   DFKIMAP(ForeignKey, ForeignKeyParentTableVersion, ParentTableVersion),
389   DFKIMAP(ForeignKey, ForeignKeyChildTableId, ChildTableId),
390   DFKIMAP(ForeignKey, ForeignKeyChildTableVersion, ChildTableVersion),
391   DFKIMAP(ForeignKey, ForeignKeyParentIndexId, ParentIndexId),
392   DFKIMAP(ForeignKey, ForeignKeyParentIndexVersion, ParentIndexVersion),
393   DFKIMAP(ForeignKey, ForeignKeyChildIndexId, ChildIndexId),
394   DFKIMAP(ForeignKey, ForeignKeyChildIndexVersion, ChildIndexVersion),
395   DFKIMAP(ForeignKey, ForeignKeyOnUpdateAction, OnUpdateAction),
396   DFKIMAP(ForeignKey, ForeignKeyOnDeleteAction, OnDeleteAction),
397 
398   DFKIMAP2(ForeignKey, ForeignKeyParentColumnsLength, ParentColumnsLength, 0,
399            MAX_ATTRIBUTES_IN_INDEX),
400   DFKIMAPB(ForeignKey, ForeignKeyParentColumns, ParentColumns, 0,
401            4*MAX_ATTRIBUTES_IN_INDEX,
402            ParentColumnsLength),
403 
404   DFKIMAP2(ForeignKey, ForeignKeyChildColumnsLength, ChildColumnsLength, 0,
405            MAX_ATTRIBUTES_IN_INDEX),
406   DFKIMAPB(ForeignKey, ForeignKeyChildColumns, ChildColumns, 0,
407            4*MAX_ATTRIBUTES_IN_INDEX,
408            ChildColumnsLength)
409 };
410 
411 //static
412 const Uint32 DictForeignKeyInfo::MappingSize =
413   sizeof(DictForeignKeyInfo::Mapping) / sizeof(SimpleProperties::SP2StructMapping);
414 
415 
416 void
init()417 DictForeignKeyInfo::ForeignKey::init()
418 {
419   bzero(Name, sizeof(Name));
420   bzero(ParentTableName, sizeof(ParentTableName));
421   bzero(ParentIndexName, sizeof(ParentIndexName));
422   bzero(ChildTableName, sizeof(ChildTableName));
423   bzero(ChildIndexName, sizeof(ChildIndexName));
424   ForeignKeyId = RNIL;
425   ForeignKeyVersion = RNIL;
426   ParentTableId = RNIL;
427   ParentTableVersion = RNIL;
428   ChildTableId = RNIL;
429   ChildTableVersion = RNIL;
430   ParentIndexId = RNIL;
431   ParentIndexVersion = RNIL;
432   ChildIndexId = RNIL;
433   ChildIndexVersion = RNIL;
434   OnUpdateAction = NDB_FK_NO_ACTION;
435   OnDeleteAction = NDB_FK_NO_ACTION;
436   ParentColumnsLength = 0;
437   ChildColumnsLength = 0;
438 }
439 
440 void
ndbout_print(const DictForeignKeyInfo::ForeignKey & fk,char * buf,size_t sz)441 ndbout_print(const DictForeignKeyInfo::ForeignKey& fk, char* buf, size_t sz)
442 {
443   BaseString::snprintf(buf, sz,
444     "fk: name:%s id:%u"
445     " parent table: name:%s id:%u"
446     " parent index: name:%s id:%u"
447     " child table: name:%s id:%u"
448     " child index: name:%s id:%u",
449     fk.Name, fk.ForeignKeyId,
450     fk.ParentTableName, fk.ParentTableId,
451     fk.ParentIndexName, fk.ParentIndexId,
452     fk.ChildTableName, fk.ChildTableId,
453     fk.ChildIndexName, fk.ChildIndexId);
454 }
455 
456 NdbOut&
operator <<(NdbOut & out,const DictForeignKeyInfo::ForeignKey & fk)457 operator<<(NdbOut& out, const DictForeignKeyInfo::ForeignKey& fk)
458 {
459   char buf[2048];
460   ndbout_print(fk, buf, sizeof(buf));
461   out << buf;
462   return out;
463 }
464