1 /*
2  * podbc.cxx
3  *
4  * Virteos ODBC Implementation for PWLib Library.
5  *
6  * Virteos is a Trade Mark of ISVO (Asia) Pte Ltd.
7  *
8  * Copyright (c) 2004 ISVO (Asia) Pte Ltd. All Rights Reserved.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  *
21  * The Original Code is derived from and used in conjunction with the
22  * pwlib Libaray of the OpenH323 Project (www.openh323.org/)
23  *
24  * The Initial Developer of the Original Code is ISVO (Asia) Pte Ltd.
25  *
26  *	 Portions: Simple ODBC Wrapper Article www.codeproject.com
27  *
28  * Contributor(s): ______________________________________.
29  *
30  * $Revision: 24971 $
31  * $Author: willamowius $
32  * $Date: 2010-12-21 05:08:30 -0600 (Tue, 21 Dec 2010) $
33  */
34 
35 #include <ptlib.h>
36 
37 #if defined(P_ODBC) && !defined(_WIN32_WCE)
38 
39 #include <ptclib/podbc.h>
40 
41 #define new PNEW
42 
43 
44 #ifdef _MSC_VER
45  #pragma warning(disable:4244)
46  #pragma warning(disable:4100)
47 #endif
48 
49 //// Utilities
50 //////////////////////////////////////////////////////////////////
51 
AddField(PODBC::Field & newField,const PString FieldName,PODBC::FieldTypes odbctype,PODBC::PwType pwtype)52 static void AddField(PODBC::Field & newField, const PString FieldName,
53 							PODBC::FieldTypes odbctype, PODBC::PwType pwtype)
54 {
55   if (newField.Name.GetLength() == 0)   /// If not already set..
56   {
57 	newField.ODBCType = odbctype;
58 	newField.Name = FieldName;
59 	newField.Type = pwtype;
60   }
61 }
62 
63 /// Simple converters
64 ///////////////////////////////////////////////////////////////////////////////////////
65 /// To Bound Data
66 
Convert(long int & data,PString field)67 static void Convert(long int & data, PString field)
68 {
69 	data = field.AsInteger();
70 }
71 
Convert(short int & data,PString field)72 static void Convert(short int & data, PString field)
73 {
74 	data = field.AsInteger();
75 }
76 
Convert(unsigned char * data,PString field)77 static void Convert(unsigned char * data, PString field)
78 {
79     data = (unsigned char *)(const char *)field;
80 }
81 
82 
Convert(unsigned char & data,PString field)83 static void Convert(unsigned char & data, PString field)
84 {
85 	int f = field.AsInteger();
86 	data = (unsigned char)f;
87 }
88 
89 
Convert(PInt64 & data,PString field)90 static void Convert(PInt64 & data, PString field)
91 {
92 	data = field.AsInt64();
93 }
94 
Convert(double & data,PString field,int Precision=PODBCRecord::Precision)95 static void Convert(double & data, PString field,int Precision = PODBCRecord::Precision)
96 {
97 	/// Reformat to the Required Decimal places
98 	data = PString(PString::Decimal,field.AsReal(),Precision).AsReal();
99 }
100 
Convert(DATE_STRUCT & data,PString field)101 static void Convert(DATE_STRUCT & data, PString field)
102 {
103 	PTime t = PTime(field);
104 
105 	data.day = t.GetDay();
106 	data.month = t.GetMonth();
107 	data.year = t.GetYear();
108 }
109 
Convert(TIME_STRUCT & data,PString field)110 static void Convert(TIME_STRUCT & data, PString field)
111 {
112 	PTime t = PTime(field);
113 
114 	data.second = t.GetSecond();
115 	data.minute = t.GetMinute();
116 	data.hour = t.GetHour();
117 }
118 
Convert(TIMESTAMP_STRUCT & data,PString field)119 static void Convert(TIMESTAMP_STRUCT & data, PString field)
120 {
121 	PTime t = PTime(field);
122 
123 	data.day = t.GetDay();
124 	data.month = t.GetMonth();
125 	data.year = t.GetYear();
126 	data.second = t.GetSecond();
127 	data.minute = t.GetMinute();
128 	data.hour = t.GetHour();
129 }
130 
Convert(SQLGUID & data,PString field)131 static void Convert(SQLGUID & data, PString field)
132 {
133 // Yet To Be Implemented.
134 	field = PString();
135 }
136 
137 
138 /// To PString
139 ///////////////////////////////////////////////////////////////////////////////////////
140 template <typename SQLField>
Convert(SQLField field)141 static PString Convert(SQLField field)
142 {
143 	return PString(field);
144 }
145 
Convert(double field,int Precision=PODBCRecord::Precision)146 static PString Convert(double field,int Precision = PODBCRecord::Precision)
147 {
148 	return PString(PString::Decimal,field,Precision);
149 }
150 
Convert(unsigned char * field)151 static PString Convert(unsigned char * field)
152 {
153 	return PString(*field);
154 }
155 
Convert(DATE_STRUCT date)156 static PString Convert(DATE_STRUCT date)
157 {
158 	return PTime(0,0,0,date.day,date.month,date.year).AsString(PODBCRecord::TimeFormat);
159 }
160 
Convert(TIME_STRUCT time)161 static PString Convert(TIME_STRUCT time)
162 {
163 	return PTime(time.second,time.minute,time.hour,0,0,0).AsString(PODBCRecord::TimeFormat);
164 }
165 
Convert(TIMESTAMP_STRUCT timestamp)166 static PString Convert(TIMESTAMP_STRUCT	timestamp)
167 {
168 	return PTime(timestamp.second,timestamp.minute,
169 		timestamp.hour,timestamp.day,timestamp.month,timestamp.year).AsString(PODBCRecord::TimeFormat);
170 }
171 
Convert(SQLGUID guid)172 static PString Convert(SQLGUID guid)
173 {
174 // To Be Implemented.
175 	return PString();
176 }
177 
178 
179 ///PODBC
180 /////////////////////////////////////////////////////////////////
181 
182 
PODBC()183 PODBC::PODBC()
184 {
185 	m_hDBC              = NULL;
186 	m_hEnv              = NULL;
187 	m_nReturn           = SQL_ERROR;
188 }
189 
~PODBC()190 PODBC::~PODBC()
191 {
192    if( m_hDBC != NULL ) {
193     m_nReturn = SQLFreeHandle( SQL_HANDLE_DBC,  m_hDBC );
194    }
195    if( m_hEnv!=NULL )
196     m_nReturn = SQLFreeHandle( SQL_HANDLE_ENV, m_hEnv );
197 }
198 
199 
Connect(LPCTSTR svSource)200 PBoolean PODBC::Connect(LPCTSTR svSource)
201 {
202    int nConnect = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_hEnv );
203    if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
204     nConnect = SQLSetEnvAttr( m_hEnv,
205                       SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0 );
206     if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
207      nConnect = SQLAllocHandle( SQL_HANDLE_DBC, m_hEnv, &m_hDBC );
208      if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
209       SQLSetConnectOption( m_hDBC,SQL_LOGIN_TIMEOUT,5 );
210       short shortResult = 0;
211       SQLTCHAR szOutConnectString[ 1024 ];
212       nConnect = SQLDriverConnect( m_hDBC,	// Connection Handle
213           NULL,                           // Window Handle
214           (SQLTCHAR*)svSource,			  // InConnectionString
215 #ifdef _WIN32
216           _tcslen(svSource),              // StringLength1
217 #else
218           strlen(svSource),
219 #endif
220           szOutConnectString,             // OutConnectionString
221           sizeof( szOutConnectString ),   // Buffer length
222           &shortResult,                   // StringLength2Ptr
223           SQL_DRIVER_NOPROMPT );          // no User prompt
224       return ((nConnect == SQL_SUCCESS) || (nConnect == SQL_SUCCESS_WITH_INFO));
225      }
226     }
227    }
228    if( m_hDBC != NULL ) {
229     m_nReturn = SQLDisconnect( m_hDBC );
230     m_nReturn = SQLFreeHandle( SQL_HANDLE_DBC,  m_hDBC );
231    }
232    if( m_hEnv!=NULL )
233     m_nReturn = SQLFreeHandle( SQL_HANDLE_ENV, m_hEnv );
234    m_hDBC              = NULL;
235    m_hEnv              = NULL;
236    m_nReturn           = SQL_ERROR;
237    return ((m_nReturn == SQL_SUCCESS) || (m_nReturn == SQL_SUCCESS_WITH_INFO));
238 }
239 
240 
Disconnect()241 void PODBC::Disconnect()
242   {
243    if( m_hDBC != NULL )
244    {
245     m_nReturn = SQLDisconnect( m_hDBC );
246     m_hDBC = NULL;
247    }
248 }
249 
250 
251 //--
252 
Connect_MSSQL(PString User,PString Pass,PString Host,PBoolean Trusted,MSSQLProtocols Proto)253 PBoolean PODBC::Connect_MSSQL(PString User,PString Pass,
254          PString Host,PBoolean Trusted,
255          MSSQLProtocols Proto)
256 {
257 	PString Network = PString();
258 
259         switch(Proto) {
260 	   case MSSQLNamedPipes:
261 		Network ="dbnmpntw";
262 		break;
263 	   case MSSQLWinSock:
264 		Network ="dbmssocn";
265 		break;
266 	   case MSSQLIPX:
267 		Network = "dbmsspxn";
268 		break;
269 	   case MSSQLBanyan:
270 		Network = "dbmsvinn";
271 		break;
272 	   case MSSQLRPC:
273 		Network = "dbmsrpcn";
274 		break;
275 	   default:
276 		Network = "dbmssocn";
277 		break;
278 	 }
279 
280 	PString ConStr = "Driver={SQL Server};Server=" + Host + ";Uid=" + User + ";Pwd=" +
281 		 Pass +";Trusted_Connection=" + (Trusted ? "Yes" : "No") + ";Network=" + Network + ";";
282 
283    return PODBC::Connect(ConStr);
284 }
285 
286 
287  //--
Connect_DB2(PFilePath DBPath)288 PBoolean PODBC::Connect_DB2(PFilePath DBPath)
289 {
290    PString ConStr ="Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=" + DBPath + ";";
291    return PODBC::Connect(ConStr);
292 }
293 
294  //--
Connect_XLS(PFilePath XLSPath,PString DefDir)295 PBoolean PODBC::Connect_XLS(PFilePath XLSPath,PString DefDir)
296 {
297    PString ConStr = "Driver={Microsoft Excel Driver (*.xls)};DriverId=790;bq="+ XLSPath
298 						+ ";DefaultDir=" + DefDir + ";";
299    return PODBC::Connect(ConStr);
300 }
301 
302  //--
Connect_TXT(PFilePath TXTPath)303 PBoolean PODBC::Connect_TXT(PFilePath TXTPath)
304 {
305    PString ConStr = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq="+ TXTPath
306 						+ ";Extensions=asc,csv,tab,txt;";
307 
308    return PODBC::Connect(ConStr);
309 }
310 
311  //--
Connect_FOX(PFilePath DBPath,PString User,PString Pass,PString Type,PBoolean Exclusive)312 PBoolean PODBC::Connect_FOX(PFilePath DBPath,PString User,
313           PString Pass,PString Type,
314           PBoolean Exclusive)
315 {
316    PString ConStr = "Driver={Microsoft Visual Foxpro Driver};Uid=" + User + ";Pwd=" + Pass
317 				+";SourceDB=" + DBPath + ";SourceType=" + Type + ";Exclusive=" + (Exclusive ? "yes": "no") + ";";
318 
319    return PODBC::Connect(ConStr);
320 }
321 
322  //--
Connect_MDB(PFilePath MDBPath,PString User,PString Pass,PBoolean Exclusive)323 PBoolean PODBC::Connect_MDB(PFilePath MDBPath,PString User,
324             PString Pass,PBoolean Exclusive)
325 {
326    PString ConStr = "Driver={Microsoft Access Driver (*.mdb)};Dbq=" + MDBPath + ";Uid=" + User +
327 	   ";Pwd=" + Pass + ";Exclusive=" + (Exclusive ? "yes" : "no");
328 
329    return PODBC::Connect(ConStr);
330 }
331 
332  //--
Connect_PDOX(PDirectory DBPath,PDirectory DefaultDir,int version)333 PBoolean PODBC::Connect_PDOX(PDirectory DBPath,PDirectory DefaultDir,int version)
334 {
335    PString driver = "3.X";
336   if (version == 4)
337     driver = "4.X";
338   if (version > 4)
339     driver = "5.X";
340 
341    PString ConStr = "Driver={Microsoft Paradox Driver (*.db )};DriverID=538;Fil=Paradox " +
342 						 driver + ";DefaultDir=" + DefaultDir +
343 						 "\\;Dbq=" + DBPath + "\\;CollatingSequence=ASCII;";
344 
345    return PODBC::Connect(ConStr);
346 }
347 
348  //--
Connect_DBASE(PDirectory DBPath)349 PBoolean PODBC::Connect_DBASE(PDirectory DBPath)
350 {
351    PString ConStr = "Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=" + DBPath + ";";
352    return PODBC::Connect(ConStr);
353 }
354  //--
Connect_Oracle(PString Server,PString User,PString Pass)355 PBoolean PODBC::Connect_Oracle(PString Server,PString User, PString Pass)
356 {
357   PString ConStr = "Driver={Microsoft ODBC for Oracle};Server=" + Server +
358 					";Uid=" + User + ";Pwd=" + Pass + ";";
359 
360   return PODBC::Connect(ConStr);
361 }
362 
363  //--
Connect_mySQL(PString User,PString Pass,PString Host,int Port,int Option)364 PBoolean PODBC::Connect_mySQL(PString User,PString Pass,PString Host, int Port,int Option)
365 {
366    PString ConStr = "Driver={MySQL ODBC 3.51 Driver};Uid=" + User + ";Pwd=" + Pass
367 				 + ";Server=" + Host + ";Port=" + PString(Port) + ";";
368 
369    return PODBC::Connect(ConStr);
370 }
371 
ConnectDB_mySQL(PString DB,PString User,PString Pass,PString Host,int Port,int Option)372 PBoolean PODBC::ConnectDB_mySQL(PString DB,PString User,PString Pass,PString Host, int Port,int Option)
373 {
374    PString ConStr = "Driver={MySQL ODBC 3.51 Driver};Database=" + DB + ";Uid=" + User
375 					+ ";Pwd=" + Pass +";Server=" + Host + ";Port=" + PString(Port) + ";";
376 
377    return PODBC::Connect(ConStr);
378 }
379 
Connect_postgreSQL(PString DB,PString User,PString Pass,PString Host,int Port,int Option)380 PBoolean PODBC::Connect_postgreSQL(PString DB,PString User,
381         PString Pass,PString Host, int Port,int Option)
382 {
383    PString ConStr = "Driver={PostgreSQL};Database=" + DB + ";Uid=" + User
384 					+ ";Pwd=" + Pass +";Server=" + Host + ";Port=" + PString(Port) + ";";
385 
386    return PODBC::Connect(ConStr);
387 }
388 
389  //--
DataSource(DataSources Source,ConnectData Data)390 PBoolean PODBC::DataSource(DataSources Source, ConnectData Data)
391 {
392    dbase = Source;
393 
394    switch (Source)
395    {
396      case PODBC::mySQL:
397        if (Data.Host.GetLength() == 0)
398          Data.Host = "localhost";
399        if (Data.Port == 0)
400          Data.Port = 3306;
401        if (Data.DefDir.GetLength() == 0) {
402          return Connect_mySQL(Data.User,Data.Pass,Data.Host,Data.Port,Data.opt);
403         } else {
404           return ConnectDB_mySQL(Data.DefDir,Data.User,Data.Pass,Data.Host,Data.Port,Data.opt);
405         }
406      case PODBC::MSSQL:
407        if (Data.Host.GetLength() == 0)
408          Data.Host = "(local)";
409          return Connect_MSSQL(Data.User,Data.Pass,Data.Host,Data.Excl_Trust, (MSSQLProtocols)Data.opt);
410      case PODBC::Oracle:
411          return Connect_Oracle(Data.Host,Data.User, Data.Pass);
412      case PODBC::IBM_DB2:
413          return Connect_DB2(Data.DBPath);
414      case PODBC::DBASE:
415          return Connect_DBASE(Data.DBPath);
416      case PODBC::Paradox:
417          return Connect_PDOX(Data.DBPath,Data.DefDir,Data.opt);
418      case PODBC::Excel:
419          return Connect_XLS(Data.DBPath,Data.DefDir);
420      case PODBC::Ascii:
421          return Connect_TXT(Data.DBPath);
422      case PODBC::Foxpro:
423          return Connect_FOX(Data.DBPath,Data.User,Data.Pass,"DBF",Data.Excl_Trust);
424      case PODBC::MSAccess:
425          return Connect_MDB(Data.DBPath,Data.User,Data.Pass,Data.Excl_Trust);
426      case PODBC::postgreSQL:
427          return Connect_postgreSQL(Data.User,Data.Pass,Data.Host,Data.Port,Data.opt);
428    };
429 
430 	return PFalse;
431 }
432 
TableList(PString option)433 PStringArray PODBC::TableList(PString option)
434 {
435     PODBCStmt data(this);
436 	return data.TableList(option);
437 }
438 
LoadTable(PString table)439 PODBC::Table PODBC::LoadTable(PString table)
440 {
441   PODBC::Table newTable(this,table);
442   return newTable;
443 }
444 
Query(PString Query)445 PBoolean PODBC::Query(PString Query)
446 {
447   if (m_hDBC == NULL)
448 	  return PFalse;
449 
450    PODBCStmt stmt(this);
451 	return stmt.Query(Query);
452 }
453 
SetPrecision(int Digit)454 void PODBC::SetPrecision(int Digit)
455 {
456 	PODBCRecord::Precision = Digit;
457 }
458 
SetTimeFormat(PTime::TimeFormat tformat)459 void PODBC::SetTimeFormat(PTime::TimeFormat tformat)
460 {
461 	PODBCRecord::TimeFormat = tformat;
462 }
463 
NeedLongDataLen()464 PBoolean PODBC::NeedLongDataLen()
465 {
466 
467   PString  f;
468 
469   SQLGetInfo(m_hDBC,SQL_NEED_LONG_DATA_LEN,
470    f.GetPointer(2),2, NULL);
471 
472 	if (f == "N")
473 		  return PFalse;
474 	else
475 		  return PTrue;
476 }
477 /////////////////////////////////////////////////////////////////////////////
478 // PODBC::Field
479 
AsString()480 PString PODBC::Field::AsString()
481 {
482 Bind & b = Data;	   /// Bound Buffer container
483 PBoolean B = isReadOnly;   /// ReadOnly Columns are not Buffer Bound and have to get Data;
484 SQLINTEGER len = MAX_DATA_LEN;
485 
486      switch (ODBCType) {
487       case PODBC::BigInt:
488         if (B)
489           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.sbint,0,&b.dataLen);
490           return Convert(b.sbint);
491 
492       case PODBC::TinyInt:
493       case PODBC::Bit:
494         if (B)
495           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.sbit,0,&b.dataLen);
496           return Convert(b.sbit);
497 
498       case PODBC::Char:
499         if (B)
500           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.suchar,0,&b.dataLen);
501           return Convert(b.suchar);
502 
503       case PODBC::Integer:
504         if (B)
505           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.slint,0,&b.dataLen);
506           return Convert(b.slint);
507 
508       case PODBC::SmallInt:
509         if (B)
510           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.ssint,0,&b.dataLen);
511           return Convert(b.ssint);
512 
513       case PODBC::Numeric:
514       case PODBC::Decimal:
515       case PODBC::Float:
516       case PODBC::Real:
517       case PODBC::Double:
518         if (B)
519           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.sdoub,0,&b.dataLen);
520           return Convert(b.sdoub,Decimals);
521 
522       /// Date Times
523       case PODBC::Date:
524         if (B)
525           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.date,0,&b.dataLen);
526           return Convert(b.date);
527 
528       case PODBC::Time:
529         if (B)
530           SQLGetData(*row->rec->Stmt,col,ODBCType,&b.time,0,&b.dataLen);
531           return Convert(b.time);
532 
533       case PODBC::TimeStamp:
534          if (B)
535            SQLGetData(*row->rec->Stmt,col,ODBCType,&b.timestamp,0,&b.dataLen);
536            return Convert(b.timestamp);
537 
538       case PODBC::Guid:
539          if (B)
540            SQLGetData(*row->rec->Stmt,col,ODBCType,&b.guid,0,&b.dataLen);
541            return Convert(b.guid);
542 
543       /// Binary/Long Data Cannot be Bound Need to get it!
544       case PODBC::Binary:
545       case PODBC::VarBinary:
546       case PODBC::LongVarBinary:
547       case PODBC::LongVarChar:
548         return row->rec->GetLongData(col);
549 
550       /// Character
551       case PODBC::DateTime:
552       case PODBC::Unknown:
553       case PODBC::VarChar:
554       default:
555         if (B)
556           SQLGetData(*row->rec->Stmt,col,ODBCType,b.sbin.GetPointer(len),len,&b.dataLen);
557           return b.sbin;
558   }
559 }
560 
SetValue(PString value)561 void PODBC::Field::SetValue(PString value)
562 {
563 
564     Bind &b = Data;
565 
566    /// If Field is marked as ReadOnly Do not Update
567    if (isReadOnly)
568         return;
569 
570    /// If Field is not Nullable and the New Value length =0 No Update.
571    if ((!isNullable) && (value.GetLength() == 0))
572     return;
573 
574 	switch (ODBCType) {
575 		case PODBC::BigInt:
576 			Convert(b.sbint,value);
577 			break;
578 
579 		case PODBC::TinyInt:
580 		case PODBC::Bit:
581 			 Convert(b.sbit,value);
582 			 break;
583 
584 		case PODBC::Char:
585 			 Convert(b.suchar,value);
586 			 break;
587 
588 		case PODBC::Integer:
589 			 Convert(b.slint,value);
590 			 break;
591 
592 		case PODBC::SmallInt:
593 			 Convert(b.ssint,value);
594 			 break;
595 
596 		case PODBC::Numeric:
597 		case PODBC::Decimal:
598 		case PODBC::Float:
599 		case PODBC::Real:
600 		case PODBC::Double:
601 			 Convert(b.sdoub,value);
602 			 break;
603 
604 	  /// Date Times
605 		case PODBC::Date:
606 			 Convert(b.date,value);
607 			 break;
608 
609 		case PODBC::Time:
610 			 Convert(b.time,value);
611 			 break;
612 
613 		case PODBC::TimeStamp:
614 			 Convert(b.timestamp,value);
615 			 break;
616 
617 		case PODBC::Guid:
618 			 Convert(b.guid,value);
619 
620 	  /// Binary Data
621 		case PODBC::Binary:
622 		case PODBC::VarBinary:
623 		case PODBC::LongVarBinary:
624 		case PODBC::LongVarChar:
625 			b.sbinlong = value;
626 				if (row->rec->dbase == PODBC::MSAccess) {
627 					b.sbinlong.SetSize(MAX_DATA_LEN * PODBCRecord::MaxCharSize);
628 					b.dataLen = b.sbinlong.GetLength();
629 				}
630 			break;
631 
632 	  /// Character
633 		case PODBC::DateTime:
634 		case PODBC::Unknown:
635 		case PODBC::VarChar:
636 		default:
637 			b.sbin = value;
638 			b.sbin.SetSize(MAX_DATA_LEN);
639 			b.dataLen = b.sbin.GetLength();
640 	};
641 }
642 
SetDefaultValues()643 void PODBC::Field::SetDefaultValues()
644 {
645   if ((isReadOnly) || (isAutoInc))
646     return;
647 
648   /// Set Default Values
649   switch (Type) {
650     case oPString:
651     case ochar:
652      if (isNullable)
653        SetValue(PString());
654      else
655        SetValue("?");
656      break;
657     case oPTime:
658       SetValue(PTime().AsString());
659       break;
660     default:
661       SetValue(0);
662   }
663 }
664 
operator =(const PString & str)665 PString PODBC::Field::operator=(const PString & str)
666 {
667 	return AsString();
668 }
669 
670 
DataFragment(PString & Buffer,PINDEX & fragment,SQLINTEGER & size)671 PBoolean PODBC::Field::DataFragment(PString & Buffer,PINDEX & fragment, SQLINTEGER & size)
672 {
673   PINDEX fragcount = PINDEX(Data.sbinlong.GetLength()/size);
674 // Value less than Buffer Size
675   if (fragcount == 0) {
676 	  Buffer = Data.sbinlong;
677 	  return PFalse;
678   }
679 // Buffer Fragment
680   if (fragcount < fragment) {
681 	  Buffer.Splice(Data.sbinlong,(fragment * size)+1,size);
682 	  fragment++;
683 	  return PTrue;
684   }
685 // Last Fragment
686   PINDEX blen = Data.sbinlong.GetLength() - (fragment * size);
687   Buffer = Data.sbinlong.Right(blen);
688   size = blen;
689   return PFalse;
690 }
691 
Post()692 PBoolean PODBC::Field::Post()
693 {
694 	return row->Post();
695 }
696 
697 /////////////////////////////////////////////////////////////////////////////
698 // PODBC::Table
699 
Table(PODBC * odbc,PString Query)700 PODBC::Table::Table(PODBC * odbc, PString Query)
701 	:	stmt(PODBCStmt(odbc))
702 {
703    PString query;
704     tableName = PString();
705 
706 // Do the Query
707     if (Query.Trim().Left(6) == "SELECT") {		// Select Query
708       query = Query;
709     } else {									// Table Query
710       tableName = Query;
711       query = "SELECT * FROM [" + tableName + "];";
712     }
713 
714     if (!stmt.Query(query))
715       return;
716 
717     // Create the Row Handler
718     RowHandler = new Row(&stmt);
719 }
720 
~Table()721 PODBC::Table::~Table()
722 {
723 }
724 
NewRow()725 PODBC::Row PODBC::Table::NewRow()
726 {
727       RowHandler->SetNewRow();
728       return *RowHandler;
729 }
730 
DeleteRow(PINDEX row)731 PBoolean PODBC::Table::DeleteRow(PINDEX row)
732 {
733       return RowHandler->Delete(row);
734 }
735 
736 
Post()737 PBoolean PODBC::Table::Post()
738 {
739       return RowHandler->Post();
740 }
741 
Rows()742 PINDEX PODBC::Table::Rows()
743 {
744       return RowHandler->RowCount;
745 }
746 
Columns()747 PINDEX PODBC::Table::Columns()
748 {
749      return RowHandler->Columns();
750 }
751 
ColumnNames()752 PStringArray PODBC::Table::ColumnNames()
753 {
754      return RowHandler->ColumnNames();
755 }
756 
operator [](PINDEX row)757 PODBC::Row & PODBC::Table::operator[] (PINDEX row)
758 {
759    if (RowHandler->Navigate(row))
760      return *RowHandler;
761 
762    return *RowHandler;
763 }
764 
RecordHandler()765 PODBC::Row & PODBC::Table::RecordHandler()
766 {
767      return *RowHandler;
768 }
769 
operator ()(PINDEX row,PINDEX col)770 PODBC::Field & PODBC::Table::operator() (PINDEX row, PINDEX col)
771 {
772 
773      RowHandler->Navigate(row);
774      return RowHandler->Column(col);
775 }
776 
Column(PINDEX col)777 PODBC::Field & PODBC::Table::Column(PINDEX col)
778 {
779      return RowHandler->Column(col);
780 }
781 
Column(PString Name)782 PODBC::Field & PODBC::Table::Column(PString Name)
783 {
784 	return RowHandler->Column(Name);
785 }
786 ///////////////////////////////////////////////////////////////////
787 // PODBC::Row
788 
Row(PODBCStmt * stmt)789 PODBC::Row::Row(PODBCStmt * stmt)
790 	: rec(new PODBCRecord(stmt))
791 {
792   /// Create a blank Row (RecordHolder) with default Recordset Info.
793 	for (PINDEX i=0; i < rec->ColumnCount(); i++)
794 	{
795           Field * nfield = new Field;
796           nfield->row = this;
797           nfield->col = i+1;
798 
799 	 // Default Attributes
800          nfield->isReadOnly = PFalse;
801          nfield->isNullable = PTrue;
802          nfield->isAutoInc = PFalse;
803          nfield->Decimals = 0;
804          nfield->LongData = stmt->GetLink()->NeedLongDataLen();
805 
806          rec->Data(i+1, *nfield);
807 
808         /// Append to PArray
809         Fields.Append(nfield);
810        }
811 
812 
813    NewRow = PFalse;
814 
815 // Attempt to get the first Record
816   if (!stmt->FetchFirst())
817     RowCount = 0;
818   else
819     RowCount = 1;
820 
821 // Get the Record Count  (Need a better way other than fetching! :-( )
822    while(stmt->Fetch())
823 	RowCount++;
824 
825   /// Put the RecordHolder to point to the First Row
826   if (RowCount > 0) {
827    stmt->FetchFirst();
828    CurRow = 1;
829   } else
830    CurRow = 0;
831 }
832 
833 
Column(PINDEX col)834 PODBC::Field & PODBC::Row::Column(PINDEX col)
835 {
836   /// Column = 0 return blank field
837   if ((col == 0) || (col > Fields.GetSize()))
838       return *(new PODBC::Field());
839 
840    return Fields[col-1];
841 }
842 
Column(PString name)843 PODBC::Field & PODBC::Row::Column(PString name)
844 {
845     PINDEX i = rec->ColumnByName(name);
846     return Column(i);
847 }
848 
Columns()849 PINDEX PODBC::Row::Columns()
850 {
851     return rec->ColumnCount();
852 }
853 
ColumnNames()854 PStringArray PODBC::Row::ColumnNames()
855 {
856     PStringArray Names;
857 
858     for (PINDEX i = 0; i < Fields.GetSize(); i++)
859     {
860       Names.AppendString(rec->ColumnName(i+1));
861     }
862     return Names;
863 }
864 
Rows()865 PINDEX PODBC::Row::Rows()
866 {
867    return RowCount;
868 }
869 
870 
operator [](PINDEX col)871 PODBC::Field & PODBC::Row::operator[] (PINDEX col)
872 {
873     return Column(col);
874 }
875 
operator [](PString col)876 PODBC::Field & PODBC::Row::operator[] (PString col)
877 {
878      PINDEX i = rec->ColumnByName(col);
879      return Column(i);
880 }
881 
SetNewRow()882 void PODBC::Row::SetNewRow()
883 {
884   CurRow = RowCount+1;
885   NewRow = PTrue;
886 
887   for (PINDEX i = 0; i < Fields.GetSize(); i++)
888   {
889      Column(i).SetDefaultValues();
890   }
891 }
892 
Navigate(PINDEX row)893 PBoolean PODBC::Row::Navigate(PINDEX row)
894 {
895    if ((row > 0) && (CurRow != row)) {
896      if (!rec->Stmt->FetchRow(row,PTrue))
897 	return PFalse;
898 
899      CurRow = row;
900    }
901   return PTrue;
902 }
903 
Post()904 PBoolean PODBC::Row::Post()
905 {
906   PBoolean Success;
907 
908   if (NewRow) {
909     NewRow = PFalse;
910     RowCount++;
911     CurRow = RowCount;
912     Success = rec->PostNew(*this);
913    } else {
914     Success = rec->PostUpdate(*this);
915    }
916 
917    return Success;
918 }
919 
920 
921 
Delete(PINDEX row)922 PBoolean PODBC::Row::Delete(PINDEX row)
923 {
924     if (row > 0) {
925       if (!Navigate(row))
926         return PFalse;
927       }
928 
929     if (!rec->PostDelete())
930      return PFalse;
931 
932     RowCount--;
933     return PTrue;
934 }
935 
936 
937 // PDSNConnection
938 /////////////////////////////////////////////////////////////////////////////////////
939 
PDSNConnection()940 PDSNConnection::PDSNConnection()
941 {
942 
943 }
944 
~PDSNConnection()945 PDSNConnection::~PDSNConnection()
946 {
947 
948 }
949 
950 
Connect(PString Source,PString Username,PString Password)951 PBoolean PDSNConnection::Connect( PString Source ,PString Username, PString Password)
952 {
953    int nConnect = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_hEnv );
954 
955     if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
956      nConnect = SQLSetEnvAttr( m_hEnv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0 );
957 
958       if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
959         nConnect = SQLAllocHandle( SQL_HANDLE_DBC, m_hEnv, &m_hDBC );
960 
961 	if( nConnect == SQL_SUCCESS || nConnect == SQL_SUCCESS_WITH_INFO ) {
962 	  SQLSetConnectOption( m_hDBC,SQL_LOGIN_TIMEOUT,5 );
963 	  nConnect=SQLConnect( m_hDBC,
964 		 ( SQLTCHAR *)(const char *)Source,SQL_NTS,
965 		 ( SQLTCHAR *)(const char *)Username,
966 		 SQL_NTS,
967 		 ( SQLTCHAR *)(const char *)Password,
968 		 SQL_NTS
969                );
970 	  return ((nConnect == SQL_SUCCESS) || (nConnect == SQL_SUCCESS_WITH_INFO));
971 	}
972       }
973     }
974 
975    if( m_hDBC != NULL ) {
976     m_nReturn = SQLDisconnect( m_hDBC );
977     m_nReturn = SQLFreeHandle( SQL_HANDLE_DBC,  m_hDBC );
978    }
979    if( m_hEnv!=NULL )
980     m_nReturn = SQLFreeHandle( SQL_HANDLE_ENV, m_hEnv );
981 
982    m_hDBC              = NULL;
983    m_hEnv              = NULL;
984    m_nReturn           = SQL_ERROR;
985 
986    return PFalse;
987 }
988  //--
PODBCStmt(PODBC * odbc)989 PODBCStmt::PODBCStmt(PODBC * odbc)
990 	: odbclink(odbc)
991 {
992    HDBC hDBCLink = *odbc;
993 
994    SQLRETURN m_nReturn;
995    m_nReturn = SQLAllocHandle( SQL_HANDLE_STMT, hDBCLink, &m_hStmt );
996    SQLSetStmtAttr(m_hStmt, SQL_ATTR_CONCURRENCY,
997                        (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
998    SQLSetStmtAttr(m_hStmt, SQL_ATTR_CURSOR_TYPE,
999                        (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);
1000    SQLSetStmtAttr(m_hStmt, SQL_ATTR_ROW_BIND_TYPE,
1001 					   (SQLPOINTER)SQL_BIND_BY_COLUMN, 0);
1002    SQLSetStmtAttr(m_hStmt, SQL_ATTR_ROW_ARRAY_SIZE,
1003 					   (SQLPOINTER)1, 0);
1004    SQLSetStmtAttr(m_hStmt, SQL_ATTR_ROW_STATUS_PTR,
1005 					   NULL, 0);
1006 
1007    dbase = odbc->dbase;
1008 
1009    if(!SQL_OK(m_nReturn))
1010     m_hStmt=SQL_NULL_HSTMT;
1011 }
1012 
1013 
~PODBCStmt()1014 PODBCStmt::~PODBCStmt()
1015 {
1016    SQLCloseCursor(m_hStmt);
1017 
1018    if(m_hStmt!=SQL_NULL_HSTMT)
1019     SQLFreeHandle(SQL_HANDLE_STMT,m_hStmt);
1020 }
1021 
IsValid()1022 PBoolean PODBCStmt::IsValid()
1023 {
1024     return m_hStmt!=SQL_NULL_HSTMT;
1025 }
1026 
1027 
GetChangedRowCount(void)1028 DWORD PODBCStmt::GetChangedRowCount(void)
1029 {
1030    SQLLEN nRows=0;
1031    if(!SQL_OK(SQLRowCount(m_hStmt,&nRows)))
1032     return 0;
1033    return nRows;
1034 }
1035 
Query(PString strSQL)1036 PBoolean PODBCStmt::Query(PString strSQL)
1037 {
1038    SQLRETURN nRet=SQLExecDirect( m_hStmt, (SQLTCHAR *)(const char *)strSQL, SQL_NTS );
1039     return SQL_OK( nRet );
1040 }
1041 
Fetch()1042 PBoolean PODBCStmt::Fetch()
1043 {
1044    return SQL_OK(SQLFetch(m_hStmt));
1045 }
1046 
FetchPrevious()1047 PBoolean PODBCStmt::FetchPrevious()
1048 {
1049    SQLRETURN nRet=SQLFetchScroll(m_hStmt,SQL_FETCH_PRIOR,0);
1050    return SQL_OK(nRet);
1051 }
1052 
FetchNext()1053 PBoolean PODBCStmt::FetchNext()
1054 {
1055    SQLRETURN nRet=SQLFetchScroll(m_hStmt,SQL_FETCH_NEXT,0);
1056    return SQL_OK(nRet);
1057 }
1058 
FetchRow(PINDEX nRow,PBoolean Absolute)1059 PBoolean PODBCStmt::FetchRow(PINDEX nRow,PBoolean Absolute)
1060 {
1061    SQLRETURN nRet=SQLFetchScroll(m_hStmt,
1062       (Absolute ? SQL_FETCH_ABSOLUTE : SQL_FETCH_RELATIVE),nRow);
1063    return SQL_OK(nRet);
1064 }
1065 
FetchFirst()1066 PBoolean PODBCStmt::FetchFirst()
1067 {
1068    SQLRETURN nRet=SQLFetchScroll(m_hStmt,SQL_FETCH_FIRST,0);
1069    return SQL_OK(nRet);
1070 }
1071 
FetchLast()1072 PBoolean PODBCStmt::FetchLast()
1073 {
1074    SQLRETURN nRet=SQLFetchScroll(m_hStmt,SQL_FETCH_LAST,0);
1075    return SQL_OK(nRet);
1076 }
1077 
Cancel()1078 PBoolean PODBCStmt::Cancel()
1079 {
1080    SQLRETURN nRet=SQLCancel(m_hStmt);
1081    return SQL_OK(nRet);
1082 }
1083 
TableList(PString option)1084 PStringArray PODBCStmt::TableList(PString option)
1085 {
1086     PString list;
1087     PString entry;
1088     SQLINTEGER len = 129;
1089     SQLLEN cb = 0;
1090     SQLRETURN nRet;
1091 
1092 /// This Statement will need reviewing as it
1093 /// depends on the Database, Might work on some
1094 /// but not on others
1095 
1096       nRet = SQLTables(m_hStmt, 0, SQL_NTS, 0, SQL_NTS,0, SQL_NTS,(unsigned char *)(const char *)option,option.GetLength());
1097 
1098 	if (SQL_OK(nRet)) {
1099 		SQLBindCol(m_hStmt, 3, SQL_C_CHAR, entry.GetPointer(len),129,&cb);
1100 
1101 		while (Fetch())
1102 		{
1103 			SQLGetData(m_hStmt, 3, SQL_C_CHAR, entry.GetPointer(len), 129, &cb);
1104 				if (entry.GetLength() > 0) {
1105 					list = list + ":" + entry;
1106 					entry.MakeEmpty();
1107 				}
1108 		}
1109 	}
1110 
1111 	return list.Tokenise(":",PFalse);
1112 }
1113 
SQL_OK(SQLRETURN res)1114 PBoolean PODBCStmt::SQL_OK(SQLRETURN res)
1115 {
1116 	if ((res==SQL_SUCCESS_WITH_INFO) || (res==SQL_SUCCESS))
1117 		  return PTrue;
1118 
1119 	if (res != SQL_NEED_DATA)
1120 			GetLastError();
1121 
1122 	return PFalse;
1123 }
1124 
GetLastError()1125 void PODBCStmt::GetLastError()
1126 {
1127 
1128   SQLRETURN   rc;
1129   SQLINTEGER    NativeError;
1130   int buflen = SQL_MAX_MESSAGE_LENGTH;
1131   SQLSMALLINT MsgLen, i = 1;
1132   PString ErrStr, Msg;
1133 
1134    while ((rc = SQLGetDiagRec(SQL_HANDLE_STMT, m_hStmt, i, (unsigned char *)ErrStr.GetPointer(6),
1135 	      &NativeError,(unsigned char *)Msg.GetPointer(buflen), buflen, &MsgLen)) != SQL_NO_DATA)
1136    {
1137 	     odbclink->OnSQLError(ErrStr, Msg);
1138       i++;
1139    }
1140 }
1141 
1142 
1143 //////////////////////////////////////////////////////////////////////////////
1144 /// PODBCRecord
1145 
1146 unsigned int PODBCRecord::Precision;
1147 int PODBCRecord::MaxCharSize;
1148 PTime::TimeFormat PODBCRecord::TimeFormat;
1149 
1150  //--
PODBCRecord(PODBCStmt * hStmt)1151 PODBCRecord::PODBCRecord(PODBCStmt * hStmt)
1152 	: Stmt(hStmt)
1153 {
1154 	m_hStmt=*hStmt;
1155 	dbase = (PODBC::DataSources)hStmt->GetDBase();  // Database name
1156 	if (!Precision)
1157           Precision = 4;
1158 	if (!TimeFormat)
1159           TimeFormat = PTime::RFC1123;
1160 	MaxCharSize = 56;  //56 Kbytes (Stupid MSAccess)
1161 }
1162 
ColumnCount()1163 PINDEX PODBCRecord::ColumnCount()
1164 {
1165    short nCols=0;
1166    if(!Stmt->SQL_OK(SQLNumResultCols(m_hStmt,&nCols)))
1167     return 0;
1168    return nCols;
1169 }
1170 
1171 
InternalBindColumn(::USHORT Column,LPVOID pBuffer,ULONG pBufferSize,LONG * pReturnedBufferSize,USHORT nType)1172 PBoolean PODBCRecord::InternalBindColumn(::USHORT Column,LPVOID pBuffer,
1173         ULONG pBufferSize,LONG * pReturnedBufferSize,
1174         USHORT nType)
1175 {
1176    SQLLEN pReturnedSize=0;
1177 
1178    SQLRETURN Ret=SQLBindCol(m_hStmt,Column,nType,
1179                pBuffer,pBufferSize,&pReturnedSize);
1180    if(*pReturnedBufferSize)
1181     *pReturnedBufferSize=pReturnedSize;
1182 cout << pReturnedSize;
1183    return Stmt->SQL_OK(Ret);
1184 }
1185 
ColumnByName(PString Column)1186 PINDEX PODBCRecord::ColumnByName(PString Column)
1187 {
1188    PINDEX nCols=ColumnCount();
1189    for(PINDEX i=1;i<(nCols+1);i++)
1190    {
1191     if(Column == ColumnName(i))
1192       return i;
1193    }
1194    return 0;
1195 }
1196 
InternalGetData(USHORT Column,LPVOID pBuffer,ULONG pBufLen,SQLINTEGER * dataLen,int Type)1197 PBoolean PODBCRecord::InternalGetData(USHORT Column, LPVOID pBuffer,
1198     ULONG pBufLen, SQLINTEGER * dataLen, int Type)
1199 {
1200    SQLLEN od=0;
1201    int Err=SQLGetData(m_hStmt,Column,Type,pBuffer,pBufLen,&od);
1202 
1203    if (!Stmt->SQL_OK(Err))
1204 		return PFalse;
1205 
1206    if(dataLen)
1207     *dataLen=od;
1208    return PTrue;
1209 }
1210 
GetLongData(PINDEX Column)1211 PString PODBCRecord::GetLongData(PINDEX Column)
1212 {
1213    PString sbin;
1214    PString Data;
1215    SQLINTEGER len = MAX_DATA_LEN;
1216    SQLINTEGER cb =0;
1217 
1218     while (InternalGetData((USHORT)Column,sbin.GetPointer(len + 1),len,&cb))
1219 	{
1220 		if (sbin.Right(1) == '\0')			// Remove Null Char
1221 			Data = Data + sbin.Left(sbin.GetLength()-1);
1222 		else
1223 			Data = Data + sbin;
1224 	}
1225 
1226 	return Data;
1227 }
1228 
Data(PINDEX Column,PODBC::Field & field)1229 void PODBCRecord::Data(PINDEX Column, PODBC::Field & field)
1230 {
1231    SQLINTEGER len = MAX_DATA_LEN;
1232 //   SQLINTEGER cb =0;
1233    PBoolean B = PTrue;    /// Bind Switch (Readonly Fields are not Bound
1234 
1235    PODBC::Field::Bind & b = field.Data;
1236    PODBC::FieldTypes ctype = ColumnType(Column);
1237 
1238  /// Set the Attributes
1239    field.isReadOnly = !IsColumnUpdatable(Column);
1240    field.isNullable	= IsColumnNullable(Column);
1241    field.isAutoInc = IsColumnAutoIndex(Column);
1242 
1243  /// Mark Columns which ReadOnly to Be Ignored when Binding.
1244    if (field.isReadOnly) B = PFalse;
1245 
1246    switch (ctype) {
1247 
1248     /// Numeric Data
1249     case PODBC::BigInt:
1250        if (B)
1251         SQLBindCol(m_hStmt, Column,SQL_C_SBIGINT, &b.sbint,0,&b.dataLen);
1252         AddField(field,ColumnName(Column),ctype, PODBC::oPInt64);
1253         break;
1254 
1255      case PODBC::TinyInt:
1256        if (B)
1257         SQLBindCol(m_hStmt, Column, SQL_C_UTINYINT, &b.sbit, 0, &b.dataLen);
1258         AddField(field,ColumnName(Column),ctype, PODBC::oshort);
1259         break;
1260 
1261      case PODBC::Bit:
1262        if (B)
1263         SQLBindCol(m_hStmt, Column, SQL_C_BIT, &b.sbit, 0, &b.dataLen);
1264         AddField(field,ColumnName(Column),ctype, PODBC::oBOOL);
1265         break;
1266 
1267      case PODBC::Char:
1268        if (B)
1269         SQLBindCol(m_hStmt, Column, SQL_C_CHAR, &b.suchar, 0, &b.dataLen);
1270         AddField(field,ColumnName(Column),ctype,PODBC::ochar);
1271         break;
1272 
1273      case PODBC::Integer:
1274        if (B)
1275         SQLBindCol(m_hStmt, Column, SQL_C_LONG, &b.slint, 0, &b.dataLen);
1276         AddField(field,ColumnName(Column),ctype,PODBC::olong);
1277         break;
1278 
1279      case PODBC::SmallInt:
1280        if (B)
1281         SQLBindCol(m_hStmt, Column, SQL_C_SSHORT, &b.ssint, 0, &b.dataLen);
1282         AddField(field,ColumnName(Column),ctype, PODBC::oint);
1283         break;
1284 
1285      case PODBC::Numeric:
1286      case PODBC::Decimal:
1287      case PODBC::Float:
1288      case PODBC::Real:
1289      case PODBC::Double:
1290        field.Decimals = ColumnPrecision(Column);
1291        if (B)
1292         SQLBindCol(m_hStmt, Column, SQL_C_DOUBLE, &b.sdoub, 0, &b.dataLen);
1293        AddField(field,ColumnName(Column),ctype,PODBC::odouble);
1294        break;
1295 
1296      // Data Structures
1297      case PODBC::Date:
1298        if (B)
1299         SQLBindCol(m_hStmt, Column, SQL_C_TYPE_DATE, &b.date, 0, &b.dataLen);
1300        AddField(field,ColumnName(Column),ctype,PODBC::oPTime);
1301        break;
1302 
1303      case PODBC::Time:
1304        if (B)
1305         SQLBindCol(m_hStmt, Column, SQL_C_TYPE_TIME, &b.time, 0, &b.dataLen);
1306        AddField(field,ColumnName(Column),ctype,PODBC::oPTime);
1307        break;
1308 
1309      case PODBC::TimeStamp:
1310        if (B)
1311          SQLBindCol(m_hStmt, Column, SQL_C_TYPE_TIMESTAMP, &b.timestamp, 0, &b.dataLen);
1312        AddField(field,ColumnName(Column),ctype,PODBC::oPTime);
1313        break;
1314 
1315      case PODBC::Guid:
1316        if (B)
1317         SQLBindCol(m_hStmt, Column, SQL_C_GUID, &b.guid, 0, &b.dataLen);
1318        AddField(field,ColumnName(Column),ctype,PODBC::oPGUID);
1319        break;
1320 
1321       /// Binary Data
1322       case PODBC::Binary:
1323       case PODBC::VarBinary:
1324       case PODBC::LongVarBinary:
1325       case PODBC::LongVarChar:
1326         if (dbase == PODBC::MSAccess) {  /// Stupid Access Stuff!
1327           if (B)
1328             SQLBindCol(m_hStmt, field.col, SQL_C_CHAR, b.sbinlong.GetPointer(len*MaxCharSize), len*MaxCharSize, &b.dataLen);
1329           else {
1330             if (B)
1331               SQLBindCol(m_hStmt, Column, SQL_LONGVARCHAR, (SQLPOINTER)Column, 0, &b.dataLen);
1332             if (field.LongData)
1333               b.dataLen = SQL_LEN_DATA_AT_EXEC(0);
1334             else
1335               b.dataLen = SQL_LEN_DATA_AT_EXEC(len);
1336           }
1337         }
1338         AddField(field,ColumnName(Column),ctype,PODBC::oPString);
1339         break;
1340 
1341       /// Character
1342       case PODBC::DateTime:
1343       case PODBC::Unknown:
1344       case PODBC::VarChar:
1345       default:
1346         b.sbin.SetSize(len+1);
1347         AddField(field,ColumnName(Column),ctype,PODBC::oPString);
1348         if (B)
1349          SQLBindCol(m_hStmt, Column, SQL_C_CHAR, b.sbin.GetPointer(len), len, &b.dataLen);
1350         break;
1351    };
1352 }
1353 
1354 
PostNew(PODBC::Row & rec)1355 PBoolean PODBCRecord::PostNew(PODBC::Row & rec)
1356 {
1357    SQLRETURN nRet;
1358 
1359    nRet = SQLBulkOperations(m_hStmt,			// Statement handle
1360 			SQL_ADD								// Operation
1361    );
1362 
1363    return InternalSaveLongData(nRet,rec);
1364 }
1365 
1366 
PostUpdate(PODBC::Row & rec)1367 PBoolean PODBCRecord::PostUpdate(PODBC::Row & rec)
1368 {
1369    SQLRETURN nRet;
1370 
1371    nRet = SQLSetPos(m_hStmt,			// Statement handle
1372 	   (unsigned short)1,				// RowNumber
1373 	   SQL_UPDATE,						// Operation
1374 	   SQL_LOCK_NO_CHANGE				// LockType
1375 	   );
1376 
1377    return InternalSaveLongData(nRet,rec);
1378 }
1379 
1380 
PostDelete(PINDEX row)1381 PBoolean PODBCRecord::PostDelete(PINDEX row)
1382 {
1383    SQLRETURN nRet;
1384 
1385    nRet = SQLSetPos(m_hStmt,			// Statement handle
1386      (unsigned short)row,				// RowNumber
1387      SQL_DELETE,						// Operation
1388      SQL_LOCK_NO_CHANGE				// LockType
1389      );
1390 
1391    return (Stmt->SQL_OK(nRet));
1392 }
1393 
InternalSaveLongData(SQLRETURN nRet,PODBC::Row & rec)1394 PBoolean PODBCRecord::InternalSaveLongData(SQLRETURN nRet, PODBC::Row & rec)
1395 {
1396 
1397    SQLPOINTER pToken;
1398    SQLINTEGER cbData;
1399    PString DataSlice;
1400    PINDEX frag, col=0;
1401 
1402  /// Everything OK but no Long Data
1403    if (Stmt->SQL_OK(nRet))
1404       return PTrue;
1405  /// Error Somewhere else.
1406    if (nRet != SQL_NEED_DATA)
1407       return PFalse;
1408 
1409 /// If More Data Required
1410    while (nRet == SQL_NEED_DATA) {
1411 	 nRet = SQLParamData(m_hStmt,&pToken);
1412 
1413    if (col != *(PINDEX*)pToken) {
1414      col = *(PINDEX*)pToken;
1415      DataSlice = PString();
1416      frag = 0;
1417      cbData = MAX_DATA_LEN;
1418    }
1419 
1420    if (nRet == SQL_NEED_DATA) {
1421      while (rec[col].DataFragment(DataSlice,frag, cbData))
1422       SQLPutData(m_hStmt,DataSlice.GetPointer(cbData),cbData);
1423    }
1424    }
1425    return PTrue;
1426 }
1427 
ColumnType(PINDEX Column)1428 PODBC::FieldTypes PODBCRecord::ColumnType( PINDEX Column )
1429 {
1430    int nType=SQL_C_DEFAULT;
1431    SQLTCHAR svColName[ 256 ]=_T("");
1432    SWORD swCol=0,swType=0,swScale=0,swNull=0;
1433    SQLULEN pcbColDef;
1434    SQLDescribeCol( m_hStmt,            // Statement handle
1435        Column,             // ColumnNumber
1436        svColName,          // ColumnName
1437        sizeof( svColName), // BufferLength
1438        &swCol,             // NameLengthPtr
1439        &swType,            // DataTypePtr
1440        &pcbColDef,         // ColumnSizePtr
1441        &swScale,           // DecimalDigitsPtr
1442        &swNull );          // NullablePtr
1443    nType=(int)swType;
1444    return( (PODBC::FieldTypes)nType );
1445 }
1446 
ColumnSize(PINDEX Column)1447 DWORD PODBCRecord::ColumnSize( PINDEX Column )
1448 {
1449 //   int nType=SQL_C_DEFAULT;
1450    SQLTCHAR svColName[ 256 ]=_T("");
1451    SWORD swCol=0,swType=0,swScale=0,swNull=0;
1452    SQLULEN pcbColDef=0;
1453    SQLDescribeCol( m_hStmt,            // Statement handle
1454        Column,             // ColumnNumber
1455        svColName,          // ColumnName
1456        sizeof( svColName), // BufferLength
1457        &swCol,             // NameLengthPtr
1458        &swType,            // DataTypePtr
1459        &pcbColDef,         // ColumnSizePtr
1460        &swScale,           // DecimalDigitsPtr
1461        &swNull );          // NullablePtr
1462    return pcbColDef;
1463 }
1464 
ColumnScale(PINDEX Column)1465 DWORD PODBCRecord::ColumnScale( PINDEX Column )
1466 {
1467 //   int nType=SQL_C_DEFAULT;
1468    SQLTCHAR svColName[ 256 ]=_T("");
1469    SWORD swCol=0,swType=0,swScale=0,swNull=0;
1470    SQLULEN pcbColDef=0;
1471    SQLDescribeCol( m_hStmt,            // Statement handle
1472        Column,             // ColumnNumber
1473        svColName,          // ColumnName
1474        sizeof( svColName), // BufferLength
1475        &swCol,             // NameLengthPtr
1476        &swType,            // DataTypePtr
1477        &pcbColDef,         // ColumnSizePtr
1478        &swScale,           // DecimalDigitsPtr
1479        &swNull );          // NullablePtr
1480    return swScale;
1481 }
1482 
ColumnName(PINDEX Column)1483 PString PODBCRecord::ColumnName(PINDEX Column) //, PString Name, SHORT NameLen )
1484 {
1485 //   int nType=SQL_C_DEFAULT;
1486    SWORD swCol=0,swType=0,swScale=0,swNull=0;
1487    SQLULEN pcbColDef=0;
1488    TCHAR Name[256]=_T("");
1489    SQLRETURN Ret=
1490     SQLDescribeCol( m_hStmt,            // Statement handle
1491        Column,               // ColumnNumber
1492        (SQLTCHAR*)(LPTSTR)Name,     // ColumnName
1493        sizeof(Name),    // BufferLength
1494        &swCol,             // NameLengthPtr
1495        &swType,            // DataTypePtr
1496        &pcbColDef,         // ColumnSizePtr
1497        &swScale,           // DecimalDigitsPtr
1498        &swNull );          // NullablePtr
1499 
1500    if (!Stmt->SQL_OK(Ret))
1501 		return PString();
1502 
1503    return Name;
1504 }
1505 
IsColumnNullable(PINDEX Column)1506 PBoolean PODBCRecord::IsColumnNullable( PINDEX Column )
1507  {
1508 //   int nType=SQL_C_DEFAULT;
1509    SQLTCHAR svColName[ 256 ]=_T("");
1510    SWORD swCol=0,swType=0,swScale=0,swNull=0;
1511    SQLULEN pcbColDef;
1512    SQLDescribeCol( m_hStmt,            // Statement handle
1513        Column,             // ColumnNumber
1514        svColName,          // ColumnName
1515        sizeof( svColName), // BufferLength
1516        &swCol,             // NameLengthPtr
1517        &swType,            // DataTypePtr
1518        &pcbColDef,         // ColumnSizePtr
1519        &swScale,           // DecimalDigitsPtr
1520        &swNull );          // NullablePtr
1521    return (swNull==SQL_NULLABLE);
1522 }
1523 
IsColumnUpdatable(PINDEX Column)1524 PBoolean PODBCRecord::IsColumnUpdatable(PINDEX Column )
1525 {
1526 
1527    SQLLEN colUpdate=0;
1528    SQLColAttribute(m_hStmt,     // StatementHandle
1529         (SQLSMALLINT)(Column),  // ColumnNumber
1530         SQL_DESC_UPDATABLE,	// FieldIdentifier
1531         NULL,			// CharacterAttributePtr
1532         0,			// BufferLength
1533         NULL,			// StringLengthPtr
1534         &colUpdate);		// NumericAttributePtr
1535    return (colUpdate != SQL_ATTR_READONLY);
1536 }
1537 
IsColumnAutoIndex(PINDEX Column)1538 PBoolean PODBCRecord::IsColumnAutoIndex(PINDEX Column )
1539 {
1540 
1541    SQLLEN colIndex=0;
1542    SQLColAttribute(m_hStmt,	// StatementHandle
1543         (SQLSMALLINT)(Column),  // ColumnNumber
1544         SQL_DESC_AUTO_UNIQUE_VALUE,  // FieldIdentifier
1545         NULL,                    // CharacterAttributePtr
1546         0,                       // BufferLength
1547         NULL,                    // StringLengthPtr
1548         &colIndex);              // NumericAttributePtr
1549    return (colIndex == SQL_TRUE);
1550 }
1551 
ColumnPrecision(PINDEX Column)1552 unsigned int PODBCRecord::ColumnPrecision(PINDEX Column )
1553 {
1554    SQLLEN coldigits=0;
1555    SQLColAttribute(m_hStmt,      // StatementHandle
1556         (SQLSMALLINT)(Column),   // ColumnNumber
1557         SQL_DESC_PRECISION,      // FieldIdentifier
1558         NULL,                    // CharacterAttributePtr
1559         0,                       // BufferLength
1560         NULL,                    // StringLengthPtr
1561         &coldigits);             // NumericAttributePtr
1562 
1563    if (Precision < (unsigned)coldigits)
1564 	   return Precision;
1565    else
1566 	   return coldigits;
1567 }
1568 
1569 #ifdef _MSC_VER
1570  #pragma warning(default:4100)
1571  #pragma warning(default:4244)
1572 #endif
1573 
1574 #endif // P_ODBC
1575 
1576