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