1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPostgreSQLDatabase.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 #include "vtkPostgreSQLDatabase.h"
21 #include "vtkPostgreSQLDatabasePrivate.h"
22 #include "vtkPostgreSQLQuery.h"
23 
24 #include "vtkSQLDatabaseSchema.h"
25 
26 #include "vtkObjectFactory.h"
27 #include "vtkStringArray.h"
28 
29 #include <sstream>
30 #include <vtksys/SystemTools.hxx>
31 
32 #include "vtkSmartPointer.h"
33 #define VTK_CREATE(classname, varname) vtkSmartPointer<classname> varname = vtkSmartPointer<classname>::New()
34 
35 #include <libpq-fe.h>
36 
37 #include <cassert>
38 
39 vtkStandardNewMacro(vtkPostgreSQLDatabase);
40 
41 // ----------------------------------------------------------------------
vtkPostgreSQLDatabase()42 vtkPostgreSQLDatabase::vtkPostgreSQLDatabase()
43 {
44   this->Connection = 0;
45   this->ConnectionMTime = this->MTime;
46 
47   this->DatabaseType = 0;
48   this->SetDatabaseType("psql");
49   this->HostName = 0;
50   this->User = 0;
51   this->Password = 0;
52   this->DatabaseName = 0;
53   this->ServerPort = -1;
54   this->ConnectOptions = 0;
55   this->LastErrorText = 0;
56   this->Tables = vtkStringArray::New();
57   this->Tables->Register(this);
58   this->Tables->Delete();
59 }
60 
61 // ----------------------------------------------------------------------
~vtkPostgreSQLDatabase()62 vtkPostgreSQLDatabase::~vtkPostgreSQLDatabase()
63 {
64   if ( this->IsOpen() )
65   {
66     this->Close();
67   }
68 
69   this->SetHostName( 0 );
70   this->SetUser( 0 );
71   this->SetDatabaseName( 0 );
72   this->SetConnectOptions( 0 );
73   this->SetDatabaseType( 0 );
74   this->SetLastErrorText( 0 );
75   this->Tables->UnRegister(this);
76 }
77 
78 // ----------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)79 void vtkPostgreSQLDatabase::PrintSelf(ostream &os, vtkIndent indent)
80 {
81   this->Superclass::PrintSelf(os, indent);
82   os << indent << "Connection: ";
83   if ( this->Connection )
84   {
85     os << this->Connection << endl;
86   }
87   else
88   {
89     os << "(null)" << endl;
90   }
91   os << indent << "DatabaseType: " << (this->DatabaseType ? this->DatabaseType : "nullptr") << endl;
92   os << indent << "HostName: " << (this->HostName ? this->HostName : "nullptr") << endl;
93   os << indent << "User: " << (this->User ? this->User : "nullptr") << endl;
94   os << indent << "Password: " << (this->Password? "(hidden)":"(none)") << endl;
95   os << indent << "DatabaseName: " << (this->DatabaseName ? this->DatabaseName : "nullptr") << endl;
96   os << indent << "ServerPort: " << this->ServerPort << endl;
97   os << indent << "ConnectOptions: " << (this->ConnectOptions ? this->ConnectOptions : "nullptr") << endl;
98   os << indent << "LastErrorText: " << this->LastErrorText << endl;
99 }
100 
101 // ----------------------------------------------------------------------
GetColumnSpecification(vtkSQLDatabaseSchema * schema,int tblHandle,int colHandle)102 vtkStdString vtkPostgreSQLDatabase::GetColumnSpecification(
103   vtkSQLDatabaseSchema* schema, int tblHandle, int colHandle )
104 {
105   std::ostringstream queryStr;
106   queryStr << schema->GetColumnNameFromHandle( tblHandle, colHandle );
107 
108   // Figure out column type
109   int colType = schema->GetColumnTypeFromHandle( tblHandle, colHandle );
110   vtkStdString colTypeStr;
111   switch ( static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>( colType ) )
112   {
113     case vtkSQLDatabaseSchema::SERIAL:
114       colTypeStr = "SERIAL";
115       break;
116     case vtkSQLDatabaseSchema::SMALLINT:
117       colTypeStr = "SMALLINT";
118       break;
119     case vtkSQLDatabaseSchema::INTEGER:
120       colTypeStr = "INTEGER";
121       break;
122     case vtkSQLDatabaseSchema::BIGINT:
123       colTypeStr = "BIGINT";
124       break;
125     case vtkSQLDatabaseSchema::VARCHAR:
126       colTypeStr = "VARCHAR";
127       break;
128     case vtkSQLDatabaseSchema::TEXT:
129       colTypeStr = "TEXT";
130       break;
131     case vtkSQLDatabaseSchema::REAL:
132       colTypeStr = "REAL";
133       break;
134     case vtkSQLDatabaseSchema::DOUBLE:
135       colTypeStr = "DOUBLE PRECISION";
136       break;
137     case vtkSQLDatabaseSchema::BLOB:
138       colTypeStr = "BYTEA";
139       break;
140     case vtkSQLDatabaseSchema::TIME:
141       colTypeStr = "TIME";
142       break;
143     case vtkSQLDatabaseSchema::DATE:
144       colTypeStr = "DATE";
145       break;
146     case vtkSQLDatabaseSchema::TIMESTAMP:
147       colTypeStr = "TIMESTAMP WITH TIME ZONE";
148       break;
149   }
150 
151   if ( colTypeStr.size() )
152   {
153     queryStr << " " << colTypeStr;
154   }
155   else // if ( colTypeStr.size() )
156   {
157     vtkGenericWarningMacro( "Unable to get column specification: unsupported data type " << colType );
158     return vtkStdString();
159   }
160 
161   // Decide whether size is allowed, required, or unused
162   int colSizeType = 0;
163   switch ( static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>( colType ) )
164   {
165     case vtkSQLDatabaseSchema::SERIAL:
166       colSizeType =  0;
167       break;
168     case vtkSQLDatabaseSchema::SMALLINT:
169       colSizeType =  0;
170       break;
171     case vtkSQLDatabaseSchema::INTEGER:
172       colSizeType =  0;
173       break;
174     case vtkSQLDatabaseSchema::BIGINT:
175       colSizeType =  0;
176       break;
177     case vtkSQLDatabaseSchema::VARCHAR:
178       colSizeType = -1;
179       break;
180     case vtkSQLDatabaseSchema::TEXT:
181       colSizeType =  0;
182       break;
183     case vtkSQLDatabaseSchema::REAL:
184       colSizeType =  0;
185       break;
186     case vtkSQLDatabaseSchema::DOUBLE:
187       colSizeType =  0;
188       break;
189     case vtkSQLDatabaseSchema::BLOB:
190       colSizeType =  0;
191       break;
192     case vtkSQLDatabaseSchema::TIME:
193       colSizeType =  1;
194       break;
195     case vtkSQLDatabaseSchema::DATE:
196       colSizeType =  0;
197       break;
198     case vtkSQLDatabaseSchema::TIMESTAMP:
199       colSizeType =  0;
200       break;
201   }
202 
203   // Specify size if allowed or required
204   if ( colSizeType )
205   {
206     int colSize = schema->GetColumnSizeFromHandle( tblHandle, colHandle );
207     // IF size is provided but absurd,
208     // OR, if size is required but not provided OR absurd,
209     // THEN assign the default size.
210     if ( ( colSize < 0 ) || ( colSizeType == -1 && colSize < 1 ) )
211     {
212       colSize = VTK_SQL_DEFAULT_COLUMN_SIZE;
213     }
214 
215     // At this point, we have either a valid size if required, or a possibly null valid size
216     // if not required. Thus, skip sizing in the latter case.
217     if ( colSize > 0 )
218     {
219       queryStr << "(" << colSize << ")";
220     }
221   }
222 
223   vtkStdString attStr = schema->GetColumnAttributesFromHandle( tblHandle, colHandle );
224   if ( attStr.size() )
225   {
226     queryStr << " " << attStr;
227   }
228 
229   return queryStr.str();
230 }
231 
232 // ----------------------------------------------------------------------
Open(const char * password)233 bool vtkPostgreSQLDatabase::Open( const char* password )
234 {
235   if ( ! this->HostName || ! this->DatabaseName )
236   {
237     this->SetLastErrorText( "Cannot open database because HostName and/or DatabaseName are null." );
238     vtkErrorMacro( << this->GetLastErrorText() );
239     return false;
240   }
241 
242   if ( this->Connection )
243   {
244     if ( this->ConnectionMTime > this->URLMTime )
245     {
246       return true; // we already had that database open.
247     }
248     this->Close(); // close the old connection before opening a new one
249   }
250 
251   std::string options;
252   options = "dbname=";
253   options += this->DatabaseName;
254 
255   if ( this->ServerPort > 0 )
256   {
257     options += " port=";
258     std::ostringstream stream;
259     stream << this->ServerPort;
260     options += stream.str();
261   }
262   if ( this->User && strlen( this->User ) > 0 )
263   {
264     options += " user=";
265     options += this->User;
266   }
267   if ( password && this->Password != password )
268   {
269     delete [] this->Password;
270     this->Password = password ? vtksys::SystemTools::DuplicateString( password ) : 0;
271   }
272   if ( this->Password && strlen( this->Password ) > 0 )
273   {
274     options += " password=";
275     options += this->Password;
276   }
277   if ( this->ConnectOptions && strlen( this->ConnectOptions ) > 0 )
278   {
279     options += this->ConnectOptions;
280   }
281 
282   // If localhost is specified, try the local socket connection
283   // first. Only if that doesn't work will we try the loopback
284   // device.
285   if ( ! strcmp( this->HostName, "localhost" ) )
286   {
287     if ( this->OpenInternal( options.c_str() ) )
288     {
289       this->SetLastErrorText( 0 );
290       return true;
291     }
292   }
293   std::string hspec( "host=" );
294   hspec += this->HostName;
295   options = hspec + " " + options;
296   if ( this->OpenInternal( options.c_str() ) )
297   {
298     this->SetLastErrorText( 0 );
299     return true;
300   }
301 
302   return false;
303 }
304 
305 // ----------------------------------------------------------------------
Close()306 void vtkPostgreSQLDatabase::Close()
307 {
308   if ( this->Connection )
309   {
310     delete this->Connection;
311     this->Connection = 0;
312     this->SetLastErrorText( 0 );
313     this->URLMTime.Modified(); // Force a re-open to occur when Open() is called.
314   }
315 }
316 
317 // ----------------------------------------------------------------------
IsOpen()318 bool vtkPostgreSQLDatabase::IsOpen()
319 {
320   return (this->Connection != 0 &&
321           this->Connection->Connection != 0 &&
322           PQstatus(this->Connection->Connection) == CONNECTION_OK);
323 }
324 
325 // ----------------------------------------------------------------------
GetQueryInstance()326 vtkSQLQuery* vtkPostgreSQLDatabase::GetQueryInstance()
327 {
328   vtkPostgreSQLQuery* query = vtkPostgreSQLQuery::New();
329   query->SetDatabase( this );
330   return query;
331 }
332 
333 // ----------------------------------------------------------------------
HasError()334 bool vtkPostgreSQLDatabase::HasError()
335 {
336   // Assume that an unopened connection is not a symptom of failure.
337   if ( this->Connection )
338   {
339     return this->LastErrorText ? true : false;
340   }
341   else
342   {
343     return false;
344   }
345 }
346 
347 // ----------------------------------------------------------------------
GetLastErrorText()348 const char* vtkPostgreSQLDatabase::GetLastErrorText()
349 {
350   return this->LastErrorText;
351 }
352 
353 // ----------------------------------------------------------------------
GetURL()354 vtkStdString vtkPostgreSQLDatabase::GetURL()
355 {
356   vtkStdString url = this->GetDatabaseType();
357   url += "://";
358   if ( this->HostName && this->DatabaseName )
359   {
360     if ( this->User && strlen( this->User ) > 0 )
361     {
362       url += this->User;
363       url += "@";
364     }
365     url += this->HostName;
366     url += "/";
367     url += this->DatabaseName;
368   }
369   return url;
370 }
371 
372 // ----------------------------------------------------------------------
ParseURL(const char * URL)373 bool vtkPostgreSQLDatabase::ParseURL( const char* URL )
374 {
375   std::string urlstr( URL ? URL : "" );
376   std::string protocol;
377   std::string username;
378   std::string password;
379   std::string hostname;
380   std::string dataport;
381   std::string database;
382 
383   // Okay now for all the other database types get more detailed info
384   if ( ! vtksys::SystemTools::ParseURL(
385       urlstr, protocol, username, password, hostname, dataport, database) )
386   {
387     vtkErrorMacro( "Invalid URL: \"" << urlstr.c_str() << "\"" );
388     return false;
389   }
390 
391   if ( protocol == "psql" )
392   {
393     this->SetUser( username.empty() ? 0 : username.c_str() );
394     this->SetPassword( password.empty() ? 0 : password.c_str() );
395     this->SetHostName( hostname.empty() ? 0 : hostname.c_str() );
396     this->SetServerPort( atoi( dataport.c_str() ) );
397     this->SetDatabaseName( database.empty() ? 0 : database.c_str() );
398     return true;
399   }
400 
401   return false;
402 }
403 
404 // ----------------------------------------------------------------------
GetTables()405 vtkStringArray* vtkPostgreSQLDatabase::GetTables()
406 {
407   this->Tables->Resize(0);
408   if ( ! this->Connection )
409   {
410     vtkErrorMacro(<< this->GetLastErrorText());
411     return this->Tables;
412   }
413 
414   // NB: Other columns of interest include table_catalog, table_schema, table_type,
415   // self_referencing_column_name, reference_generation, user_defined_type_catalog,
416   // user_defined_type_schema, user_defined_type_name, is_insertable_into, is_typed,
417   // commit_action
418   vtkSQLQuery* query = this->GetQueryInstance();
419   query->SetQuery(
420     "SELECT table_name FROM information_schema.tables"
421     "  WHERE table_schema='public' and table_type='BASE TABLE'" );
422   bool status = query->Execute();
423 
424   if ( ! status )
425   {
426     vtkErrorMacro(<< "Database returned error: " << query->GetLastErrorText());
427     this->SetLastErrorText(query->GetLastErrorText());
428     query->Delete();
429     return this->Tables;
430   }
431   vtkDebugMacro(<< "GetTables(): SQL query succeeded.");
432   while ( query->NextRow() )
433   {
434     this->Tables->InsertNextValue( query->DataValue( 0 ).ToString() );
435   }
436   query->Delete();
437   this->SetLastErrorText(nullptr);
438   return this->Tables;
439 }
440 
441 // ----------------------------------------------------------------------
GetRecord(const char * table)442 vtkStringArray* vtkPostgreSQLDatabase::GetRecord( const char* table )
443 {
444   // NB: There are *too many* other column names to list. Even the ones
445   // currently in the query below are probably over the top. But there's
446   // just so much peanut-buttery goodness in the table, I couldn't resist.
447   vtkSQLQuery* query = this->GetQueryInstance();
448   vtkStdString text(
449     "SELECT column_name,column_default,data_type,is_nullable,character_maximum_length,numeric_precision,datetime_precision"
450     "  FROM information_schema.columns"
451     "  WHERE table_name='" );
452   text += table;
453   text += "' ORDER BY ordinal_position";
454 
455   query->SetQuery( text.c_str() );
456   bool status = query->Execute();
457   if ( ! status )
458   {
459     vtkErrorMacro(<< "GetRecord(" << table << "): Database returned error: "
460                   << query->GetLastErrorText());
461     this->SetLastErrorText(query->GetLastErrorText());
462     query->Delete();
463     return 0;
464   }
465 
466   // Each row in the results that come back from this query
467   // describes a single column in the table.
468   vtkStringArray* results = vtkStringArray::New();
469 
470   while ( query->NextRow() )
471   {
472     results->InsertNextValue( query->DataValue( 0 ).ToString() );
473   }
474 
475   query->Delete();
476   this->SetLastErrorText(0);
477   return results;
478 }
479 
480 // ----------------------------------------------------------------------
IsSupported(int feature)481 bool vtkPostgreSQLDatabase::IsSupported( int feature )
482 {
483   switch (feature)
484   {
485     case VTK_SQL_FEATURE_BLOB:
486     case VTK_SQL_FEATURE_LAST_INSERT_ID:
487     case VTK_SQL_FEATURE_NAMED_PLACEHOLDERS:
488     case VTK_SQL_FEATURE_POSITIONAL_PLACEHOLDERS:
489     case VTK_SQL_FEATURE_PREPARED_QUERIES:
490     case VTK_SQL_FEATURE_TRANSACTIONS:
491     case VTK_SQL_FEATURE_UNICODE:
492     case VTK_SQL_FEATURE_BATCH_OPERATIONS:
493     case VTK_SQL_FEATURE_QUERY_SIZE:
494     case VTK_SQL_FEATURE_TRIGGERS:
495       return true;
496     default:
497     {
498     vtkErrorMacro(
499       << "Unknown SQL feature code " << feature << "!  See "
500       << "vtkSQLDatabase.h for a list of possible features.");
501     return false;
502     };
503   }
504 }
505 
506 // ----------------------------------------------------------------------
GetDatabases()507 vtkStringArray* vtkPostgreSQLDatabase::GetDatabases()
508 {
509   if ( ! this->Connection )
510   {
511     vtkErrorMacro( "Must be connected to a server to get a list of databases." );
512     return 0;
513   }
514 
515   vtkSQLQuery* query = this->GetQueryInstance();
516   if ( ! query )
517   {
518     vtkErrorMacro( "Could not create a query." );
519     return 0;
520   }
521 
522   query->SetQuery( "SELECT datname FROM pg_database" );
523   if ( ! query->Execute() )
524   {
525     query->Delete();
526     return 0;
527   }
528   vtkStringArray* dbNames = vtkStringArray::New();
529   while ( query->NextRow() )
530   {
531     dbNames->InsertNextValue( query->DataValue( 0 ).ToString() );
532   }
533   query->Delete();
534   return dbNames;
535 }
536 
537 // ----------------------------------------------------------------------
CreateDatabase(const char * dbName,bool dropExisting)538 bool vtkPostgreSQLDatabase::CreateDatabase( const char* dbName, bool dropExisting )
539 {
540   if ( ! dbName )
541   {
542     vtkErrorMacro( "Databases must have a non-nullptr name" );
543     return false;
544   }
545 
546   bool dropCurrentlyConnected = false;
547   if ( this->DatabaseName && ! strcmp( this->DatabaseName, dbName ) )
548   {
549     dropCurrentlyConnected = true;
550     if ( dropExisting )
551     {
552       // we can't drop a database we're connected to...
553       this->SetDatabaseName( "template1" );
554       this->Open();
555     }
556     else
557     {
558       // this will fail... let it. then report the error via LastErrorText
559     }
560   }
561 
562   if ( ! this->Connection )
563   {
564     if ( this->DatabaseName && ! strcmp( this->DatabaseName, dbName ) )
565     {
566       // we can't connect to a database we haven't created yet and aren't connected to...
567       this->SetDatabaseName( "template1" );
568       dropCurrentlyConnected = true;
569     }
570     bool err = true;
571     if ( this->DatabaseName && this->HostName )
572     {
573       err = this->Open() ? false : true;
574     }
575     if ( err )
576     {
577       vtkErrorMacro( "Must be connected to a server to create a database." );
578       return false;
579     }
580   }
581 
582   if ( dropExisting )
583   {
584     this->DropDatabase( dbName );
585   }
586 
587   std::string qstr( "CREATE DATABASE \"" );
588   qstr += dbName;
589   qstr += "\"";
590   vtkSQLQuery *query = this->GetQueryInstance();
591   query->SetQuery(qstr.c_str());
592   if (query->Execute() == false)
593   {
594     this->SetLastErrorText(query->GetLastErrorText());
595     vtkErrorMacro(
596       "Could not create database \"" << dbName << "\". "
597       << this->GetLastErrorText() << "\n");
598     query->Delete();
599     return false;
600   }
601 
602   query->Delete();
603   this->SetLastErrorText(0);
604   if ( dropCurrentlyConnected )
605   {
606     this->SetDatabaseName( dbName );
607     this->Open();
608   }
609   return true;
610 }
611 
612 // ----------------------------------------------------------------------
DropDatabase(const char * dbName)613 bool vtkPostgreSQLDatabase::DropDatabase( const char* dbName )
614 {
615   if ( ! dbName || strlen( dbName ) == 0 )
616   {
617     vtkErrorMacro( "DropDatabase called with an empty database name" );
618     return false;
619   }
620 
621   if ( ! strcmp( dbName, this->DatabaseName ) )
622   {
623     // Can't drop database we're connected to... connect to the default db.
624     this->SetDatabaseName( "template1" );
625   }
626 
627   if ( ! this->Connection )
628   {
629     bool err = true;
630     if ( this->DatabaseName && this->HostName )
631     {
632       err = this->Open() ? false : true;
633     }
634     if ( err )
635     {
636       vtkErrorMacro( "Must be connected to a server to create a database." );
637       return false;
638     }
639   }
640 
641   std::string qstr( "DROP DATABASE IF EXISTS \"" );
642   qstr += dbName;
643   qstr += "\"";
644   vtkSQLQuery *query = this->GetQueryInstance();
645   query->SetQuery(qstr.c_str());
646   if (query->Execute() == false)
647   {
648     this->SetLastErrorText(query->GetLastErrorText());
649     vtkErrorMacro(<<"Could not drop database \""
650                   << dbName << "\".  "
651                   << query->GetLastErrorText());
652     query->Delete();
653     return false;
654   }
655   this->SetLastErrorText(0);
656   query->Delete();
657   return true;
658 }
659 
NullTrailingWhitespace(char * msg)660 void vtkPostgreSQLDatabase::NullTrailingWhitespace( char* msg )
661 {
662   // overwrite any blank space at the end of a message with nullptr.
663   // PostgreSQL error messages are terminated with a newline, which
664   // does not work well with VTK's already lengthy error output.
665   int msglen = strlen( msg );
666   char* tail = msg + msglen - 1;
667   while ( tail > msg && isspace( *tail ) )
668     *(tail--) = 0;
669 }
670 
OpenInternal(const char * connectionOptions)671 bool vtkPostgreSQLDatabase::OpenInternal( const char* connectionOptions )
672 {
673   assert(this->Connection == nullptr);
674   this->Connection = new vtkPostgreSQLDatabasePrivate;
675   this->Connection->Connection = PQconnectdb(connectionOptions);
676   if (PQstatus(this->Connection->Connection) == CONNECTION_OK)
677   {
678     this->SetLastErrorText(0);
679     this->UpdateDataTypeMap();
680     return true;
681   }
682   else
683   {
684     this->SetLastErrorText(PQerrorMessage(this->Connection->Connection));
685     vtkErrorMacro(<<"Unable to open database connection. "
686                   << this->GetLastErrorText());
687     delete this->Connection;
688     this->Connection = 0;
689     return false;
690   }
691 }
692 
693 // ----------------------------------------------------------------------
694 
UpdateDataTypeMap()695 void vtkPostgreSQLDatabase::UpdateDataTypeMap()
696 {
697   if (!this->IsOpen())
698   {
699     return;
700   }
701 
702   this->Connection->DataTypeMap.clear();
703 
704   vtkSQLQuery *typeQuery = this->GetQueryInstance();
705   typeQuery->SetQuery("SELECT oid, typname, typlen FROM pg_type");
706   bool status = typeQuery->Execute();
707   if (!status)
708   {
709     vtkErrorMacro(<<"I was totally surprised to see the data type query fail.  Error message: "
710                   << typeQuery->GetLastErrorText());
711     typeQuery->Delete();
712   }
713   else
714   {
715     while (typeQuery->NextRow())
716     {
717       Oid oid;
718       vtkStdString name;
719       int len;
720 
721       // Caution: this assumes that the Postgres OID type is a 32-bit
722       // unsigned int.
723       oid = typeQuery->DataValue(0).ToUnsignedInt();
724       name = typeQuery->DataValue(1).ToString();
725       len = typeQuery->DataValue(2).ToInt();
726 
727       if ( name == "int8" || ( name == "oid" && len == 8 ) )
728       {
729         this->Connection->DataTypeMap[ oid ] = VTK_TYPE_INT64;
730       }
731       else if ( name == "int4" || ( name == "oid" && len == 4 ) )
732       {
733         this->Connection->DataTypeMap[ oid ] = VTK_TYPE_INT32;
734       }
735       else if ( name == "int2" )
736       {
737         this->Connection->DataTypeMap[ oid ] = VTK_TYPE_INT16;
738       }
739       else if ( name == "char" )
740       {
741         this->Connection->DataTypeMap[ oid ] = VTK_TYPE_INT8;
742       }
743       else if ( name == "time_stamp" )
744       {
745         this->Connection->DataTypeMap[ oid ] = VTK_TYPE_INT64;
746       }
747       else if ( name == "float4" )
748       {
749         this->Connection->DataTypeMap[ oid ] = VTK_FLOAT;
750       }
751       else if ( name == "float8" )
752       {
753         this->Connection->DataTypeMap[ oid ] = VTK_DOUBLE;
754       }
755       else if ( name == "abstime" || name == "reltime" )
756       {
757         this->Connection->DataTypeMap[ oid ] = ( len == 4 ? VTK_TYPE_INT32 : VTK_TYPE_INT64 );
758       }
759       else if ( name == "text" )
760       {
761         this->Connection->DataTypeMap[ oid ] = VTK_STRING;
762       }
763     } // done looping over rows
764   } // done with "query is successful"
765   typeQuery->Delete();
766 }
767 
768