1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkSQLDatabaseSchema.cxx
5 
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16   Copyright 2008 Sandia Corporation.
17   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18   the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20 
21 #include "vtkToolkits.h"
22 #include "vtkSQLDatabaseSchema.h"
23 
24 #include "vtkObjectFactory.h"
25 #include "vtkStdString.h"
26 
27 #include <cstdarg> // va_list
28 
29 #include <vector>
30 
31 // ----------------------------------------------------------------------
32 vtkStandardNewMacro(vtkSQLDatabaseSchema);
33 
34 // ----------------------------------------------------------------------
35 class vtkSQLDatabaseSchemaInternals
36 {
37 public:  // NB: use of string instead of char* here to avoid leaks on destruction.
38   struct Statement
39   {
40     vtkStdString Name;
41     vtkStdString Action; // may have backend-specific stuff
42     vtkStdString Backend;  // only active for this backend, if != ""
43   };
44 
45   struct Column
46   {
47     vtkSQLDatabaseSchema::DatabaseColumnType Type;
48     int Size; // used when required, ignored otherwise (e.g. varchar)
49     vtkStdString Name;
50     vtkStdString Attributes; // may have backend-specific stuff
51   };
52 
53   struct Index
54   {
55     vtkSQLDatabaseSchema::DatabaseIndexType Type;
56     vtkStdString Name;
57     std::vector<vtkStdString> ColumnNames;
58   };
59 
60   struct Trigger
61   {
62     vtkSQLDatabaseSchema::DatabaseTriggerType Type;
63     vtkStdString Name;
64     vtkStdString Action; // may have backend-specific stuff
65     vtkStdString Backend; // only active for this backend, if != ""
66   };
67 
68   struct Option
69   {
70     vtkStdString Text;
71     vtkStdString Backend;
72   };
73 
74   struct Table
75   {
76     vtkStdString Name;
77     std::vector<Column> Columns;
78     std::vector<Index> Indices;
79     std::vector<Trigger> Triggers;
80     std::vector<Option> Options;
81   };
82 
83   std::vector<Statement> Preambles;
84   std::vector<Table> Tables;
85 };
86 
87 // ----------------------------------------------------------------------
vtkSQLDatabaseSchema()88 vtkSQLDatabaseSchema::vtkSQLDatabaseSchema()
89 {
90   this->Name = nullptr;
91   this->Internals = new vtkSQLDatabaseSchemaInternals;
92 }
93 
94 // ----------------------------------------------------------------------
~vtkSQLDatabaseSchema()95 vtkSQLDatabaseSchema::~vtkSQLDatabaseSchema()
96 {
97   this->SetName( nullptr );
98   delete this->Internals;
99 }
100 
101 // ----------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)102 void vtkSQLDatabaseSchema::PrintSelf( ostream& os, vtkIndent indent )
103 {
104   this->Superclass::PrintSelf( os, indent );
105   os << indent << "Name: ";
106   if (this->Name)
107   {
108     os << this->Name << "\n";
109   }
110   else
111   {
112     os << "(null)" << "\n";
113   }
114   os << indent << "Internals: " << this->Internals << "\n";
115 }
116 
117 // ----------------------------------------------------------------------
AddPreamble(const char * preName,const char * preAction,const char * preBackend)118 int vtkSQLDatabaseSchema::AddPreamble(
119   const char* preName, const char* preAction, const char* preBackend )
120 {
121   if ( ! preName )
122   {
123     vtkErrorMacro( "Cannot add preamble with empty name" );
124     return -1;
125   }
126 
127   vtkSQLDatabaseSchemaInternals::Statement newPre;
128   int preHandle = static_cast<int>(this->Internals->Preambles.size());
129   newPre.Name = preName;
130   newPre.Action = preAction;
131   newPre.Backend = preBackend;
132   this->Internals->Preambles.push_back( newPre );
133   return preHandle;
134 }
135 
136 // ----------------------------------------------------------------------
AddTable(const char * tblName)137 int vtkSQLDatabaseSchema::AddTable( const char* tblName )
138 {
139   if ( ! tblName )
140   {
141     vtkErrorMacro( "Cannot add table with empty name" );
142     return -1;
143   }
144 
145   vtkSQLDatabaseSchemaInternals::Table newTbl;
146   int tblHandle = static_cast<int>(this->Internals->Tables.size());
147   newTbl.Name = tblName;
148   this->Internals->Tables.push_back( newTbl );
149   return tblHandle;
150 }
151 
152 // ----------------------------------------------------------------------
AddColumnToIndex(int tblHandle,int idxHandle,int colHandle)153 int vtkSQLDatabaseSchema::AddColumnToIndex(
154   int tblHandle, int idxHandle, int colHandle )
155 {
156   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
157   {
158     vtkErrorMacro( "Cannot add column to index of non-existent table " << tblHandle );
159     return -1;
160   }
161 
162   vtkSQLDatabaseSchemaInternals::Table* table = &this->Internals->Tables[tblHandle];
163   if ( colHandle < 0 || colHandle >= static_cast<int>( table->Columns.size() ) )
164   {
165     vtkErrorMacro( "Cannot add non-existent column " << colHandle << " in table " << tblHandle );
166     return -1;
167   }
168 
169   if ( idxHandle < 0 || idxHandle >= static_cast<int>( table->Indices.size() ) )
170   {
171     vtkErrorMacro( "Cannot add column to non-existent index " << idxHandle << " of table " << tblHandle );
172     return -1;
173   }
174 
175   table->Indices[idxHandle].ColumnNames.push_back( table->Columns[colHandle].Name );
176   return static_cast<int>( table->Indices[idxHandle].ColumnNames.size() - 1 );
177 }
178 
179 // ----------------------------------------------------------------------
AddColumnToTable(int tblHandle,int colType,const char * colName,int colSize,const char * colOpts)180 int vtkSQLDatabaseSchema::AddColumnToTable(
181   int tblHandle, int colType, const char* colName,
182   int colSize, const char* colOpts )
183 {
184   if ( ! colName )
185   {
186     vtkErrorMacro( "Cannot add column with empty name to table " << tblHandle );
187     return -1;
188   }
189 
190   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
191   {
192     vtkErrorMacro( "Cannot add column to non-existent table " << tblHandle );
193     return -1;
194   }
195 
196   // DCT: This trick avoids copying a Column structure the way push_back would:
197   int colHandle = static_cast<int>(this->Internals->Tables[tblHandle].Columns.size());
198   this->Internals->Tables[tblHandle].Columns.resize( colHandle + 1 );
199   vtkSQLDatabaseSchemaInternals::Column* column = &this->Internals->Tables[tblHandle].Columns[colHandle];
200   column->Type = static_cast<DatabaseColumnType>( colType );
201   column->Size = colSize;
202   column->Name = colName;
203   column->Attributes = colOpts;
204   return colHandle;
205 }
206 
207 // ----------------------------------------------------------------------
AddIndexToTable(int tblHandle,int idxType,const char * idxName)208 int vtkSQLDatabaseSchema::AddIndexToTable(
209   int tblHandle, int idxType, const char* idxName )
210 {
211   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
212   {
213     vtkErrorMacro( "Cannot add index to non-existent table " << tblHandle );
214     return -1;
215   }
216 
217   int idxHandle = static_cast<int>(this->Internals->Tables[tblHandle].Indices.size());
218   this->Internals->Tables[tblHandle].Indices.resize( idxHandle + 1 );
219   vtkSQLDatabaseSchemaInternals::Index* index = &this->Internals->Tables[tblHandle].Indices[idxHandle];
220   index->Type = static_cast<DatabaseIndexType>( idxType );
221   index->Name = idxName;
222   return idxHandle;
223 }
224 
225 // ----------------------------------------------------------------------
AddTriggerToTable(int tblHandle,int trgType,const char * trgName,const char * trgAction,const char * trgBackend)226 int vtkSQLDatabaseSchema::AddTriggerToTable(
227   int tblHandle, int trgType, const char* trgName,
228   const char* trgAction, const char* trgBackend )
229 {
230   if ( ! trgName )
231   {
232     vtkErrorMacro( "Cannot add trigger with empty name to table " << tblHandle );
233     return -1;
234   }
235 
236   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
237   {
238     vtkErrorMacro( "Cannot add trigger to non-existent table " << tblHandle );
239     return -1;
240   }
241 
242   int trgHandle = static_cast<int>(this->Internals->Tables[tblHandle].Triggers.size());
243   this->Internals->Tables[tblHandle].Triggers.resize( trgHandle + 1 );
244   vtkSQLDatabaseSchemaInternals::Trigger* trigger = &this->Internals->Tables[tblHandle].Triggers[trgHandle];
245   trigger->Type = static_cast<DatabaseTriggerType>( trgType );
246   trigger->Name = trgName;
247   trigger->Action = trgAction;
248   trigger->Backend = trgBackend;
249   return trgHandle;
250 }
251 
252 // ----------------------------------------------------------------------
AddOptionToTable(int tblHandle,const char * optText,const char * optBackend)253 int vtkSQLDatabaseSchema::AddOptionToTable(
254   int tblHandle, const char* optText, const char* optBackend )
255 {
256   if ( ! optText )
257   {
258     vtkErrorMacro( "Cannot add nullptr option to table " << tblHandle );
259     return -1;
260   }
261 
262   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
263   {
264     vtkErrorMacro( "Cannot add option to non-existent table " << tblHandle );
265     return -1;
266   }
267 
268   int optHandle = static_cast<int>( this->Internals->Tables[tblHandle].Options.size() );
269   this->Internals->Tables[tblHandle].Options.resize( optHandle + 1 );
270   vtkSQLDatabaseSchemaInternals::Option* optn = &this->Internals->Tables[tblHandle].Options[optHandle];
271   optn->Text = optText;
272   optn->Backend = optBackend ? optBackend : VTK_SQL_ALLBACKENDS;
273   return optHandle;
274 }
275 
276 // ----------------------------------------------------------------------
GetPreambleHandleFromName(const char * preName)277 int vtkSQLDatabaseSchema::GetPreambleHandleFromName( const char* preName )
278 {
279   int i;
280   int ntab = static_cast<int>(this->Internals->Preambles.size());
281   vtkStdString preNameStr( preName );
282   for ( i = 0; i < ntab; ++i )
283   {
284     if ( this->Internals->Preambles[i].Name == preNameStr )
285     {
286       return i;
287     }
288   }
289   return -1;
290 }
291 
292 // ----------------------------------------------------------------------
GetPreambleNameFromHandle(int preHandle)293 const char* vtkSQLDatabaseSchema::GetPreambleNameFromHandle( int preHandle )
294 {
295   if ( preHandle < 0 || preHandle >= this->GetNumberOfPreambles() )
296   {
297     vtkErrorMacro( "Cannot get name of non-existent preamble " << preHandle );
298     return nullptr;
299   }
300 
301   return this->Internals->Preambles[preHandle].Name;
302 }
303 
304 // ----------------------------------------------------------------------
GetPreambleActionFromHandle(int preHandle)305 const char* vtkSQLDatabaseSchema::GetPreambleActionFromHandle( int preHandle )
306 {
307   if ( preHandle < 0 || preHandle >= this->GetNumberOfPreambles() )
308   {
309     vtkErrorMacro( "Cannot get action of non-existent preamble " << preHandle );
310     return nullptr;
311   }
312 
313   return this->Internals->Preambles[preHandle].Action;
314 }
315 
316 // ----------------------------------------------------------------------
GetPreambleBackendFromHandle(int preHandle)317 const char* vtkSQLDatabaseSchema::GetPreambleBackendFromHandle( int preHandle )
318 {
319   if ( preHandle < 0 || preHandle >= this->GetNumberOfPreambles() )
320   {
321     vtkErrorMacro( "Cannot get backend of non-existent preamble " << preHandle );
322     return nullptr;
323   }
324 
325   return this->Internals->Preambles[preHandle].Backend;
326 }
327 
328 // ----------------------------------------------------------------------
GetTableHandleFromName(const char * tblName)329 int vtkSQLDatabaseSchema::GetTableHandleFromName( const char* tblName )
330 {
331   int i;
332   int ntab = static_cast<int>(this->Internals->Tables.size());
333   vtkStdString tblNameStr( tblName );
334   for ( i = 0; i < ntab; ++i )
335   {
336     if ( this->Internals->Tables[i].Name == tblNameStr )
337     {
338       return i;
339     }
340   }
341   return -1;
342 }
343 
344 // ----------------------------------------------------------------------
GetTableNameFromHandle(int tblHandle)345 const char* vtkSQLDatabaseSchema::GetTableNameFromHandle( int tblHandle )
346 {
347   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
348   {
349     vtkErrorMacro( "Cannot get name of non-existent table " << tblHandle );
350     return nullptr;
351   }
352 
353   return this->Internals->Tables[tblHandle].Name;
354 }
355 
356 // ----------------------------------------------------------------------
GetIndexHandleFromName(const char * tblName,const char * idxName)357 int vtkSQLDatabaseSchema::GetIndexHandleFromName(
358   const char* tblName, const char* idxName )
359 {
360   int tblHandle = this->GetTableHandleFromName( tblName );
361   if ( tblHandle < 0 )
362   {
363     return -1;
364   }
365 
366   int i;
367   int nidx = static_cast<int>(this->Internals->Tables[tblHandle].Indices.size());
368   vtkStdString idxNameStr( idxName );
369   for ( i = 0; i < nidx ; ++ i )
370   {
371     if ( this->Internals->Tables[tblHandle].Indices[i].Name == idxNameStr )
372     {
373       return i;
374     }
375   }
376   return -1;
377 }
378 
379 // ----------------------------------------------------------------------
GetIndexNameFromHandle(int tblHandle,int idxHandle)380 const char* vtkSQLDatabaseSchema::GetIndexNameFromHandle(
381   int tblHandle, int idxHandle )
382 {
383   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
384   {
385     vtkErrorMacro( "Cannot get name of an index in non-existent table " << tblHandle );
386     return nullptr;
387   }
388 
389   if ( idxHandle < 0 || idxHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Indices.size() ) )
390   {
391     vtkErrorMacro( "Cannot get name of non-existent index " << idxHandle << " in table " << tblHandle );
392     return nullptr;
393   }
394 
395   return this->Internals->Tables[tblHandle].Indices[idxHandle].Name;
396 }
397 
398 // ----------------------------------------------------------------------
GetIndexTypeFromHandle(int tblHandle,int idxHandle)399 int vtkSQLDatabaseSchema::GetIndexTypeFromHandle(
400   int tblHandle, int idxHandle )
401 {
402   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
403   {
404     vtkErrorMacro( "Cannot get type of an index in non-existent table " << tblHandle );
405     return -1;
406   }
407 
408   if ( idxHandle < 0 || idxHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Indices.size() ) )
409   {
410     vtkErrorMacro( "Cannot get type of non-existent index " << idxHandle << " in table " << tblHandle );
411     return -1;
412   }
413 
414   return static_cast<int>( this->Internals->Tables[tblHandle].Indices[idxHandle].Type );
415 }
416 
417 // ----------------------------------------------------------------------
GetIndexColumnNameFromHandle(int tblHandle,int idxHandle,int cnmHandle)418 const char* vtkSQLDatabaseSchema::GetIndexColumnNameFromHandle(
419   int tblHandle, int idxHandle, int cnmHandle )
420 {
421   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
422   {
423     vtkErrorMacro( "Cannot get column name of an index in non-existent table " << tblHandle );
424     return nullptr;
425   }
426 
427   if ( idxHandle < 0 || idxHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Indices.size() ) )
428   {
429     vtkErrorMacro( "Cannot get column name of non-existent index " << idxHandle << " in table " << tblHandle );
430     return nullptr;
431   }
432 
433   if ( cnmHandle < 0 || cnmHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Indices[idxHandle].ColumnNames.size() ) )
434   {
435     vtkErrorMacro( "Cannot get column name of non-existent column " << cnmHandle << " of index " << idxHandle << " in table " << tblHandle );
436     return nullptr;
437   }
438 
439   return this->Internals->Tables[tblHandle].Indices[idxHandle].ColumnNames[cnmHandle];
440 }
441 
442 // ----------------------------------------------------------------------
GetColumnHandleFromName(const char * tblName,const char * colName)443 int vtkSQLDatabaseSchema::GetColumnHandleFromName(
444   const char* tblName, const char* colName )
445 {
446   int tblHandle = this->GetTableHandleFromName( tblName );
447   if ( tblHandle < 0 )
448   {
449     return -1;
450   }
451 
452   int i;
453   int ncol = static_cast<int>(this->Internals->Tables[tblHandle].Columns.size());
454   vtkStdString colNameStr( colName );
455   for ( i = 0; i < ncol ; ++ i )
456   {
457     if ( this->Internals->Tables[tblHandle].Columns[i].Name == colNameStr )
458     {
459       return i;
460     }
461   }
462   return -1;
463 }
464 
465 // ----------------------------------------------------------------------
GetColumnNameFromHandle(int tblHandle,int colHandle)466 const char* vtkSQLDatabaseSchema::GetColumnNameFromHandle(
467   int tblHandle, int colHandle )
468 {
469   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
470   {
471     vtkErrorMacro( "Cannot get name of a column in non-existent table " << tblHandle );
472     return nullptr;
473   }
474 
475   if ( colHandle < 0 || colHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Columns.size() ) )
476   {
477     vtkErrorMacro( "Cannot get name of non-existent column " << colHandle << " in table " << tblHandle );
478     return nullptr;
479   }
480 
481   return this->Internals->Tables[tblHandle].Columns[colHandle].Name;
482 }
483 
484 // ----------------------------------------------------------------------
GetColumnTypeFromHandle(int tblHandle,int colHandle)485 int vtkSQLDatabaseSchema::GetColumnTypeFromHandle(
486   int tblHandle, int colHandle )
487 {
488   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
489   {
490     vtkErrorMacro( "Cannot get type of a column in non-existent table " << tblHandle );
491     return -1;
492   }
493 
494   if ( colHandle < 0 || colHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Columns.size() ) )
495   {
496     vtkErrorMacro( "Cannot get type of non-existent column " << colHandle << " in table " << tblHandle );
497     return -1;
498   }
499 
500   return static_cast<int>( this->Internals->Tables[tblHandle].Columns[colHandle].Type );
501 }
502 
503 // ----------------------------------------------------------------------
GetColumnSizeFromHandle(int tblHandle,int colHandle)504 int vtkSQLDatabaseSchema::GetColumnSizeFromHandle(
505   int tblHandle, int colHandle )
506 {
507   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
508   {
509     vtkErrorMacro( "Cannot get size of a column in non-existent table " << tblHandle );
510     return -1;
511   }
512 
513   if ( colHandle < 0 || colHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Columns.size() ) )
514   {
515     vtkErrorMacro( "Cannot get size of non-existent column " << colHandle << " in table " << tblHandle );
516     return -1;
517   }
518 
519   return static_cast<int>( this->Internals->Tables[tblHandle].Columns[colHandle].Size );
520 }
521 
522 // ----------------------------------------------------------------------
GetColumnAttributesFromHandle(int tblHandle,int colHandle)523 const char* vtkSQLDatabaseSchema::GetColumnAttributesFromHandle(
524   int tblHandle,  int colHandle )
525 {
526   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
527   {
528     vtkErrorMacro( "Cannot get attributes of a column in non-existent table " << tblHandle );
529     return nullptr;
530   }
531 
532   if ( colHandle < 0 || colHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Columns.size() ) )
533   {
534     vtkErrorMacro( "Cannot get attributes of non-existent column " << colHandle << " in table " << tblHandle );
535     return nullptr;
536   }
537 
538   return this->Internals->Tables[tblHandle].Columns[colHandle].Attributes;
539 }
540 
541 // ----------------------------------------------------------------------
GetTriggerHandleFromName(const char * tblName,const char * trgName)542 int vtkSQLDatabaseSchema::GetTriggerHandleFromName(
543   const char* tblName, const char* trgName )
544 {
545   int tblHandle = this->GetTableHandleFromName( tblName );
546   if ( tblHandle < 0 )
547   {
548     return -1;
549   }
550 
551   int i;
552   int ntrg = static_cast<int>(this->Internals->Tables[tblHandle].Triggers.size());
553   vtkStdString trgNameStr( trgName );
554   for ( i = 0; i < ntrg ; ++ i )
555   {
556     if ( this->Internals->Tables[tblHandle].Triggers[i].Name == trgNameStr )
557     {
558       return i;
559     }
560   }
561   return -1;
562 }
563 
564 // ----------------------------------------------------------------------
GetTriggerNameFromHandle(int tblHandle,int trgHandle)565 const char* vtkSQLDatabaseSchema::GetTriggerNameFromHandle(
566   int tblHandle, int trgHandle )
567 {
568   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
569   {
570     vtkErrorMacro( "Cannot get name of a trigger in non-existent table " << tblHandle );
571     return nullptr;
572   }
573 
574   if ( trgHandle < 0 || trgHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Triggers.size() ) )
575   {
576     vtkErrorMacro( "Cannot get name of non-existent trigger " << trgHandle << " in table " << tblHandle );
577     return nullptr;
578   }
579 
580   return this->Internals->Tables[tblHandle].Triggers[trgHandle].Name;
581 }
582 
583 // ----------------------------------------------------------------------
GetTriggerTypeFromHandle(int tblHandle,int trgHandle)584 int vtkSQLDatabaseSchema::GetTriggerTypeFromHandle(
585   int tblHandle, int trgHandle )
586 {
587   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
588   {
589     vtkErrorMacro( "Cannot get type of a trigger in non-existent table " << tblHandle );
590     return -1;
591   }
592 
593   if ( trgHandle < 0 || trgHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Triggers.size() ) )
594   {
595     vtkErrorMacro( "Cannot get type of non-existent trigger " << trgHandle << " in table " << tblHandle );
596     return -1;
597   }
598 
599   return this->Internals->Tables[tblHandle].Triggers[trgHandle].Type;
600 }
601 
602 // ----------------------------------------------------------------------
GetTriggerActionFromHandle(int tblHandle,int trgHandle)603 const char* vtkSQLDatabaseSchema::GetTriggerActionFromHandle(
604   int tblHandle, int trgHandle )
605 {
606   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
607   {
608     vtkErrorMacro( "Cannot get action of a trigger in non-existent table " << tblHandle );
609     return nullptr;
610   }
611 
612   if ( trgHandle < 0 || trgHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Triggers.size() ) )
613   {
614     vtkErrorMacro( "Cannot get action of non-existent trigger " << trgHandle << " in table " << tblHandle );
615     return nullptr;
616   }
617 
618   return this->Internals->Tables[tblHandle].Triggers[trgHandle].Action;
619 }
620 
621 // ----------------------------------------------------------------------
GetTriggerBackendFromHandle(int tblHandle,int trgHandle)622 const char* vtkSQLDatabaseSchema::GetTriggerBackendFromHandle(
623   int tblHandle, int trgHandle )
624 {
625   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
626   {
627     vtkErrorMacro( "Cannot get backend of a trigger in non-existent table " << tblHandle );
628     return nullptr;
629   }
630 
631   if ( trgHandle < 0 || trgHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Triggers.size() ) )
632   {
633     vtkErrorMacro( "Cannot get backend of non-existent trigger " << trgHandle << " in table " << tblHandle );
634     return nullptr;
635   }
636 
637   return this->Internals->Tables[tblHandle].Triggers[trgHandle].Backend;
638 }
639 
640 // ----------------------------------------------------------------------
GetOptionTextFromHandle(int tblHandle,int optHandle)641 const char* vtkSQLDatabaseSchema::GetOptionTextFromHandle(
642   int tblHandle, int optHandle )
643 {
644   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
645   {
646     vtkErrorMacro( "Cannot get text of an option in non-existent table " << tblHandle );
647     return nullptr;
648   }
649 
650   if ( optHandle < 0 || optHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Options.size() ) )
651   {
652     vtkErrorMacro( "Cannot get text of non-existent option " << optHandle << " in table " << tblHandle );
653     return nullptr;
654   }
655 
656   return this->Internals->Tables[tblHandle].Options[optHandle].Text.c_str();
657 }
658 
659 // ----------------------------------------------------------------------
GetOptionBackendFromHandle(int tblHandle,int optHandle)660 const char* vtkSQLDatabaseSchema::GetOptionBackendFromHandle(
661   int tblHandle, int optHandle )
662 {
663   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
664   {
665     vtkErrorMacro( "Cannot get backend of an option in non-existent table " << tblHandle );
666     return nullptr;
667   }
668 
669   if ( optHandle < 0 || optHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Options.size() ) )
670   {
671     vtkErrorMacro( "Cannot get backend of non-existent option " << optHandle << " in table " << tblHandle );
672     return nullptr;
673   }
674 
675   return this->Internals->Tables[tblHandle].Options[optHandle].Backend.c_str();
676 }
677 
678 // ----------------------------------------------------------------------
AddTableMultipleArguments(const char * tblName,...)679 int vtkSQLDatabaseSchema::AddTableMultipleArguments( const char* tblName, ... )
680 {
681   int tblHandle = this->AddTable( tblName );
682   int token;
683   int dtyp;
684   int size;
685   int curIndexHandle;
686   const char* name;
687   const char* attr;
688   const char* bcke;
689 
690   va_list args;
691   va_start( args, tblName );
692   while ( ( token = va_arg( args, int ) ) != END_TABLE_TOKEN )
693   {
694     switch ( token )
695     {
696       case COLUMN_TOKEN:
697         dtyp = va_arg( args, int );
698         name = va_arg( args, const char* );
699         size = va_arg( args, int );
700         attr = va_arg( args, const char* );
701         this->AddColumnToTable( tblHandle, dtyp, name, size, attr );
702         break;
703       case INDEX_TOKEN:
704         dtyp = va_arg( args, int );
705         name = va_arg( args, const char* );
706         curIndexHandle = this->AddIndexToTable( tblHandle, dtyp, name );
707         while ( ( token = va_arg( args, int ) ) != END_INDEX_TOKEN )
708         {
709           name = va_arg( args, const char* );
710           dtyp = this->GetColumnHandleFromName( tblName, name );
711           this->AddColumnToIndex( tblHandle, curIndexHandle, dtyp );
712         }
713         break;
714       case TRIGGER_TOKEN:
715         dtyp = va_arg( args, int );
716         name = va_arg( args, const char* );
717         attr = va_arg( args, const char* );
718         bcke = va_arg( args, const char* );
719         this->AddTriggerToTable( tblHandle, dtyp, name, attr, bcke );
720         break;
721       case OPTION_TOKEN:
722         attr = va_arg( args, const char* );
723         bcke = va_arg( args, const char* );
724         this->AddOptionToTable( tblHandle, attr, bcke );
725         break;
726       default:
727       {
728         vtkErrorMacro( "Bad token " << token << " passed to AddTable" );
729         va_end( args );
730         return -1;
731       }
732     }
733   }
734   va_end( args );
735   return tblHandle;
736 }
737 
738 // ----------------------------------------------------------------------
Reset()739 void vtkSQLDatabaseSchema::Reset()
740 {
741   this->Internals->Tables.clear();
742 }
743 
744 // ----------------------------------------------------------------------
GetNumberOfPreambles()745 int vtkSQLDatabaseSchema::GetNumberOfPreambles()
746 {
747   return static_cast<int>(this->Internals->Preambles.size());
748 }
749 
750 // ----------------------------------------------------------------------
GetNumberOfTables()751 int vtkSQLDatabaseSchema::GetNumberOfTables()
752 {
753   return static_cast<int>(this->Internals->Tables.size());
754 }
755 
756 // ----------------------------------------------------------------------
GetNumberOfColumnsInTable(int tblHandle)757 int vtkSQLDatabaseSchema::GetNumberOfColumnsInTable( int tblHandle )
758 {
759   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
760   {
761     vtkErrorMacro( "Cannot get the number of columns of non-existent table " << tblHandle );
762     return -1;
763   }
764 
765   return static_cast<int>(this->Internals->Tables[tblHandle].Columns.size());
766 }
767 
768 // ----------------------------------------------------------------------
GetNumberOfIndicesInTable(int tblHandle)769 int vtkSQLDatabaseSchema::GetNumberOfIndicesInTable( int tblHandle )
770 {
771   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
772   {
773     vtkErrorMacro( "Cannot get the number of indices of non-existent table " << tblHandle );
774     return -1;
775   }
776 
777   return static_cast<int>(this->Internals->Tables[tblHandle].Indices.size());
778 }
779 
780 // ----------------------------------------------------------------------
GetNumberOfColumnNamesInIndex(int tblHandle,int idxHandle)781 int vtkSQLDatabaseSchema::GetNumberOfColumnNamesInIndex( int tblHandle, int idxHandle )
782 {
783   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
784   {
785     vtkErrorMacro( "Cannot get the number of column names in index of non-existent table " << tblHandle );
786     return -1;
787   }
788 
789   if ( idxHandle < 0 || idxHandle >= static_cast<int>( this->Internals->Tables[tblHandle].Indices.size() ) )
790   {
791     vtkErrorMacro( "Cannot get the number of column names of non-existent index " << idxHandle << " in table " << tblHandle );
792     return -1;
793   }
794 
795   return static_cast<int>(this->Internals->Tables[tblHandle].Indices[idxHandle].ColumnNames.size());
796 }
797 
798 // ----------------------------------------------------------------------
GetNumberOfTriggersInTable(int tblHandle)799 int vtkSQLDatabaseSchema::GetNumberOfTriggersInTable( int tblHandle )
800 {
801   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
802   {
803     vtkErrorMacro( "Cannot get the number of triggers of non-existent table " << tblHandle );
804     return -1;
805   }
806 
807   return static_cast<int>(this->Internals->Tables[tblHandle].Triggers.size());
808 }
809 
810 // ----------------------------------------------------------------------
GetNumberOfOptionsInTable(int tblHandle)811 int vtkSQLDatabaseSchema::GetNumberOfOptionsInTable( int tblHandle )
812 {
813   if ( tblHandle < 0 || tblHandle >= this->GetNumberOfTables() )
814   {
815     vtkErrorMacro( "Cannot get the number of options of non-existent table " << tblHandle );
816     return -1;
817   }
818 
819   return static_cast<int>(this->Internals->Tables[tblHandle].Options.size());
820 }
821