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