1 /*
2  * podbc.h
3  *
4  * Virteos ODBC Implementation for PWLib Library.
5  *
6  * Virteos is a Trade Mark of ISVO (Asia) Pte Ltd.
7  *
8  * Copyright (c) 2005 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: 24177 $
31  * $Author: rjongbloed $
32  * $Date: 2010-04-05 06:52:04 -0500 (Mon, 05 Apr 2010) $
33  */
34 
35 /**
36   ODBC Support for PWLIB
37 
38   Class Description
39    PODBC        :  Main DataBase Connection Class (Derive Class for Error Handling)
40    PODBC::ConnectData :  Class used to store information for Connecting to DataSource
41    PODBC::Table    :  Retrieved Data Structure (RecordSet) from Table or Select SQL Query
42    PODBC::Row      :  Record Pointer Class for the PODBC::Table (PArray of Fields)
43    PODBC::Field    :  Database Field Information (Field Structure & Data(Bound))
44    PODBC::Field:Bind  :  DataTypes Bound to the RecordSet (change with Record Navigation)
45    PDSNConnection    :  Derived Class of PODBC for ODBC Configured Connections
46    PODBCStmt      :  Wrapper for RecordSet (Internal)
47    PODBCRecord    :  Handle Retrieve/Post/Bind Data from RecordSet (Internal)
48 
49   Example of Use
50 
51 <pre><code>
52   PODBC link;
53   PODBC::ConnectData data;
54   data.DBPath = "test.mdb";
55 
56   if (link.DataSource(PODBC::MSAccess,data)) {
57     // Load a Database Table (could also be a SELECT Query)
58       PODBC::Table table(&link,"FooTable");
59   // Bind to Column 1
60       PODBC::Field & field = table.Column(1):
61     // Display Contents
62       cout << " Value " << field.AsString(); << endl;
63   // Move to Record 2 of fooTable
64       table[2];
65   // Display contents of Record 2 Column 1
66       cout << " Value " << field.AsString(); << endl;
67   // Set New Value for Record 2 Field 1 of FooTable
68       field.SetValue("NewValue");
69   // Send Update to Database.
70       field.Post();
71 
72     // To Add New Record.(with Default Values)
73       table.NewRow();
74   // Alter the Value of field 1
75       field.SetValue("Somethng");
76   // Post the New Field to the Database
77       field.Post();
78 
79     // Run General Query;
80       PString SQLStmt = "INSERT foo into [FooTable] ..."
81     Link.Query(SQLStmt);
82   }
83 // Disconnect from ODBC Source
84   link.Disconnect();
85 
86 </code></pre>
87 */
88 //--
89 
90 #ifndef PTLIB_PODBC_H
91 #define PTLIB_PODBC_H
92 
93 #if _MSC_VER > 1000
94 #pragma once
95 #endif // _MSC_VER > 1000
96 
97 
98 #if defined(P_ODBC) && !defined(_WIN32_WCE)
99 
100 #include <odbcinst.h>
101 #include <sql.h>
102 #include <sqlext.h>
103 
104 #ifdef _MSC_VER
105  #include <tchar.h>
106  #pragma comment(lib,"odbc32.lib")
107  #pragma comment(lib,"odbcCP32.lib")
108 #else
109 
110   #ifdef UNICODE
111   typedef WCHAR                 TCHAR;
112   typedef LPWSTR                LPTSTR;
113   typedef LPCWSTR               LPCTSTR;
114   // Needs a definition one day ... #define _T(x)
115   #else
116   typedef CHAR                  TCHAR;
117   typedef LPSTR                 LPTSTR;
118   typedef LPCSTR                LPCTSTR;
119   #define _T(x) x
120   #endif
121 
122 #endif // _MSC_VER
123 
124 // Max SQL String Data Length
125 #define MAX_DATA_LEN 1024
126 
127 /** PODBC Statement Class
128   This class is use to parse store queries and Fetch data
129   It is not designed to process the actual data only access it.
130   PODBC::Record is used to Bind/Retrieve/Store Data Elements. .
131 */
132 
133 
134 class PODBC;
135 class PODBCRecord;
136 
137 
138 class PODBCStmt : public PObject
139 {
140     PCLASSINFO(PODBCStmt, PObject);
141 
142   public:
143     /**@name Constructor/Deconstructor */
144     //@{
145     /** Constructor PODBC (Datasources call) or thro' DSNConnection (Connection call).
146     In General this class is constructed within the PODBC::Table Class.
147     */
148     PODBCStmt(PODBC * odbc);
149 
150     /** Deconstructor. This Class should be available for the duration of which
151     a specific query/table is required and be deconstructed at the time of
152     the PODBC::Table deconstruction.
153     */
154     ~PODBCStmt();
155     //@}
156 
157     /**@name Handles */
158     //@{
159     /** Statement Handle Created by the Query Function.
160     */
HSTMT()161     operator HSTMT() { return m_hStmt; };
162     //@}
163 
164 
165     /**@name Data Management */
166     //@{
167     /** IsValid Checks to ensure a Handle has been allocated and
168     is effective.
169     */
170     PBoolean IsValid();
171 
172     /** GetChangedRowCount retreives the number of rows updated/altered by
173     UPDATE/INSERT statements.
174     */
175     DWORD GetChangedRowCount(void);
176 
177     /** Query function is the Main function to pass SQL statements to retreive/
178     add/Modify database data. It accepts generally acceptable SQL Statements.
179     ie. Select * from [table-x]
180     */
181     PBoolean Query(PString strSQL);
182     //@}
183 
184     /**@name Data Retrieval */
185     //@{
186     /** Fetch General call to retreive the next row of data.
187     */
188     PBoolean Fetch();
189 
190     /** FetchRow More detailed fetching of Rows. This allows you to fetch an
191     Absolute row or a row relative to the current row fetched.
192     */
193     PBoolean FetchRow(PINDEX nRow,PBoolean Absolute=1);
194 
195     /** FetchPrevious Fetch the previous Row from current row.
196     */
197     PBoolean FetchPrevious();
198 
199     /** FetchNext: Fetch the Next row.
200     */
201     PBoolean FetchNext();
202 
203     /** FetchFirst Fetch the First row in the RecordSet
204     */
205     PBoolean FetchFirst();
206 
207     /** FetchLast Fetch the Last row in the RecordSet
208     */
209     PBoolean FetchLast();
210 
211     /** Cancel the Current Statement
212     */
213     PBoolean Cancel();
214     //@}
215 
216     /**@name Utilities */
217     //@{
218     /** Retreive the List of Tables from the current Datasource
219     The option field can be used to specify the Table Types
220     ie "TABLE" for Tables or "VIEW" for preconfigured datasource
221     queries. *Further investigation is required*
222     */
223     PStringArray TableList(PString option = "");
224 
225 
226     /** Is the SQL Instruction OK
227     If an Error is detected then GetLastError is called
228     to Retrieve the SQL Error Information and Returns false
229     */
230     PBoolean SQL_OK(SQLRETURN res);
231 
232     /** Get the Last Error
233     This returns the Error ID & String to PODBC::OnSQLError
234     */
235     void GetLastError();
236 
GetLink()237     PODBC * GetLink() const { return odbclink; }
GetDBase()238     int GetDBase() const { return dbase; }
239     //@}
240 
241   protected:
242     HSTMT   m_hStmt;
243     PODBC * odbclink; /// Reference to the PODBC Class
244     int     dbase;    /// Database Type connecting to
245 };
246 
247 
248 
249 /** PODBC Class
250   The Main ODBC class. This Class should be used in the there is
251   not a preconfigured DSN setup in the MDAC. This class will use
252   the applicable ODBC drivers to connect to a compliant Datasource.
253   It Supports a wide variety of Datasources but others can added
254   by simply creating your custom connection string and then calling
255   PODBC::Connect. For Defined sources the PODBC::DataSource function
256   should be used.
257 */
258 
259 class PODBC  : public PObject
260 {
261     PCLASSINFO(PODBC, PObject);
262 
263   public:
264     /**@name Constructor/Deconstructor */
265     //@{
266     /** Constructor
267     */
268     PODBC();
269 
270     /** Deconstructor
271     */
272     ~PODBC();
273     //@}
274 
275     /**@name Enumerators */
276     //@{
277     /** Raw SQL data type codes Refer <sql.h> SQL_*
278     This list is not inclusive. If an item
279     is not listed or Unknown it is treated
280     as a character string.
281 
282     */
283     enum FieldTypes
284     {
285       LongVarChar   =-1,
286       Binary        =-2,
287       VarBinary     =-3,
288       LongVarBinary =-4,
289       BigInt        =-5,
290       TinyInt       =-6,
291       Bit           =-7,   /// Boolean
292       Guid          =-11,
293       Unknown       = 0,
294       Char          = 1,
295       Numeric       = 2,
296       Decimal       = 3,
297       Integer       = 4,
298       SmallInt      = 5,
299       Float         = 6,
300       Real          = 7,
301       Double        = 8,
302       DateTime      = 9,
303       VarChar       =12,
304       Date          =91,    /// Structure
305       Time          =92,    /// Structure
306       TimeStamp     =93     /// Structure  PTime
307     };
308 
309     /** Converted Pwlib Field Types.
310     Data is stored as a PString
311     and the pwType enumerator indicates
312     the conversion required on the PODBC::Field.
313     */
314     enum PwType
315     {
316       oPString,   // String Value
317       oBOOL,      // Boolean
318       ochar,      // Character
319       oshort,     // Short
320       oint,       // Integer  use .AsInteger()
321       olong,      // long
322       odouble,    // Double   use .AsReal()
323       oPBYTEArray,// Binary Data
324       oPInt64,    // BigInt  use .AsInt64()
325       oPTime,     // Time    use  PTime( "Value" )
326       oPGUID      // GUID    use  PGUID( "Value" ) To Be Implemented...?
327     };
328 
329     /** Datasources that are supported by this implementation
330     used in the PODBC::DataSource Function.
331     */
332 
333     enum DataSources
334     {
335       mySQL,
336       MSSQL,
337       Oracle,
338       IBM_DB2,
339       DBASE,
340       Paradox,
341       Excel,
342       Ascii,
343       Foxpro,
344       MSAccess,
345       postgreSQL
346     };
347 
348     /** MSSQL protocols.If your interested?
349     */
350     enum MSSQLProtocols
351     {
352       MSSQLNamedPipes,
353       MSSQLWinSock,
354       MSSQLIPX,
355       MSSQLBanyan,
356       MSSQLRPC
357     };
358 
359     //@}
360 
361     /**@name Connection Class */
362     //@{
363     /** This class is a multipurpose use
364     class for storing parameters when
365     initiating connection to DataSource.
366     Not all field are required. By default
367     all non-essential params are set to a
368     datasource specific default value.
369     */
370     class ConnectData
371     {
372     public:
373       PFilePath DBPath;    /// Database file Path (not Oracle,xxSQL)
374       PString DefDir;     /// Used with Paradox/DBase/Excel (& mySQL db)
375       PString User;       /// UserName
376       PString Pass;       /// Password
377       PBoolean Excl_Trust;     /// Whether Datasource is locked or Trusted.
378       PString Host;       /// URL for Host Datasouce xxSQL
379       int Port;         /// Port to connect to mySQL
380       int opt;         /// General Option Value.mySQL & Paradox
381     };
382     //@}
383 
384 
385     /**@name Database Field Class */
386     //@{
387     /** Class for Field Data
388     */
389     class Row;
390     class Field : public PObject
391     {
392         PCLASSINFO(Field, PObject);
393       public:
394 
395         /** SQL compliant Bound DataTypes.
396         The appropriate Field is bound
397         to the SQL Driver and alters
398         when a new record is fetched.
399         */
400         class Bind
401         {
402           public:
403             PString          sbin;      /// Strings & Binary Data
404             PString          sbinlong;  /// Long Data
405             short int        ssint;     /// Short Integer    SQLSMALLINT
406             long int         slint;     /// Integer        SQLINTEGER
407             double           sdoub;     /// Double        SQLDOUBLE
408             unsigned char    sbit;      /// Bit          SQLCHAR
409             unsigned char *  suchar;    /// Unsigned char    SQLCHAR *
410             PInt64           sbint;     /// Bit Integer      SQLBIGINT
411             DATE_STRUCT      date;      /// Date Structure
412             TIME_STRUCT      time;      /// Time Structure
413             TIMESTAMP_STRUCT timestamp; /// TimeStamp Structure
414             SQLGUID          guid;      /// GUID Structure (not Fully Supported)
415             SQLLEN           dataLen;   /// DataLength pointer (StrLen_or_Ind for Col Bind)
416         };
417 
418         /** Post the Changes back to the Database
419         */
420         PBoolean Post();
421 
422         /** Returns a String representation of the field.
423         */
424         PString operator=(const PString & str);
425 
426         /** Display the Field Data as String
427         */
428         PString AsString();
429 
430         /** Set the Field Data. Note a Post() must be called
431         to post the changes back to the database.
432         */
433         void SetValue(PString value);  /// Set the Value
434 
435         /** Initialise/Set the Default values for Field of New Record
436         */
437         void SetDefaultValues();
438 
439         /** DataFragment Data is broken into fragment to be passed
440         to the Database
441         */
442         PBoolean DataFragment(PString & Buffer ,PINDEX & fragment, SQLINTEGER & size);
443 
444         /** Settings
445         */
446         /// Data
447         Bind  Data;       /// Data Field to ODBC Bind to
448         PwType  Type;       /// pwlib Type for conversion
449         FieldTypes ODBCType;   /// ODBC Type (For saving/Conversion)
450 
451         /// Column
452         PString Name;       /// Column Name
453         PINDEX col;       /// Column Number (For Saving/Conversion)
454 
455         /// Column Attributes
456         PBoolean isReadOnly;     /// Is Field Readonly
457         PBoolean isNullable;     /// Allows Nulls
458         PBoolean isAutoInc;     /// Field AutoIncrements
459         int Decimals;       /// Number of decimal places to Round
460         PBoolean LongData;     /// LongData Length is Required
461 
462         /// RecordHolder Reference
463         Row * row;       /// Back Reference to the Row
464     };
465     //@}
466 
467 
468     /**@name Database Row Class */
469     //@{
470     /** This class functions as a simple wrapper
471     of the PODBCStmt class to fetch/Save
472     data to the Datasource. Data is fetched
473     on a need to basis and not cached except
474     to create a new row.
475     */
476     class Row : public PObject
477     {
478       public:
479 
480         /** Constructor
481         Create a Dummy row of data to act as a
482         Record Marker. Template Field are created
483         and Stored in a PARRAY.
484         */
485         Row(PODBCStmt * stmt);
486 
487         /** Retrieve Field Data given the specifed column.
488         Note: Columns atart at 1 and not exceed PODBCStmt::GetColumnCount()
489         */
490         Field & Column(PINDEX col);
491 
492         /** Retreive Field Data given the Column Name
493         */
494         Field & Column(PString name);
495 
496         /** Retrieve the Column Names
497         */
498         PStringArray ColumnNames();
499 
500         /** Columns. The Number of Columns in the RecordSet
501         */
502         PINDEX Columns();
503 
504         /** Rows  The Number of Rows
505         */
506         PINDEX Rows();
507 
508         /** Retrieve Field Data given specified column
509         */
510         Field & operator[] (PINDEX col);
511 
512         /** Retrieve Field Data given the column Name.
513         */
514         Field & operator[] (PString col);
515 
516         /** Navigate to Specified Row
517         */
518         PBoolean Navigate(PINDEX row);
519 
520         /** SetNewRow Set New Row for input
521         */
522         void SetNewRow();
523 
524         /** Post the Row back to the Database.
525         When Row::NewRow is true the data
526         can be posted back to the Database;
527         If Edit Invoked then releasea the
528         RowHandler for Navigation.
529         */
530         PBoolean Post();
531 
532         /** Delete the Current Record from the
533         RecordSet
534         */
535         PBoolean Delete(PINDEX row =0);
536 
537         PODBCRecord * rec;      /// Record Structure
538 
539         PINDEX CurRow;          /// Current Row
540         PBoolean NewRow;        /// Flag to Indicate New Row (requires either Post or Delete)
541         PINDEX RowCount;      /// Number of Rows.
542 
543       protected:
544         PArray<Field> Fields;    /// PODBC::Field Array Cache (Used for New Row)
545     };
546     //@}
547 
548     /** PODBC::Table
549     This is the main Class to access Data returned by a Select Query.
550     The Table does not actually create the RecordSet but acts as a wrapper
551     to the driver to access the cached data in the Driver.
552     */
553     class Table : public PObject
554     {
555       public:
556 
557         /**@name Constructor/Deconstructor */
558         //@{
559         /** Constructor
560         Using the HDBC and TableName/Select SQL Query
561         creates a virtual Table in the OBDC driver.
562         */
563         Table(PODBC * odbc, PString Query);
564 
565         /** Deconstructor
566         */
567         ~Table();
568         //@}
569 
570         /**@name Data Storage */
571         //@{
572         /** Add New Row
573         */
574         Row NewRow();
575 
576         /** Delete Row 0 indicates Current Row
577         */
578         PBoolean DeleteRow(PINDEX row = 0);
579 
580         /** Post Update back to Database
581         */
582         PBoolean Post();
583         //@}
584 
585         /**@name Utilities */
586         //@{
587         /** Rows. Returns the Number of Rows in the Resultant RecordSet
588         */
589         PINDEX Rows();
590 
591         /** Columns. Returns the Number of Columns in the Resultant RecordSet
592         */
593         PINDEX Columns();
594 
595         /** ColumnNames. Return the list of column Names of the Resultant RecordSet
596         */
597         PStringArray ColumnNames();
598 
599         /** Obtain the Record Handler. This can be used as a Template to obtain
600         Record Information. A call to tablename[i] will update the recordHandler
601         with the Values contained in i Record.
602         */
603         Row & RecordHandler();
604 
605         /** Row return the fetched row in the Cached RecordSet. An Array of PODBC::Field
606         */
607         Row & operator[] (PINDEX row);
608 
609         /** Returns the Field data at a predetermined position in the Resultant
610         RecordSet. It Fetches the Row than isolates the Column from the fetched
611         data.
612         */
613         Field & operator() (PINDEX row, PINDEX col);
614 
615         /** Returns the indicated Column Holder for the RecordSet,
616         This can be used for iterative Row calls.
617         */
618         Field & Column(PINDEX col);
619 
620         /** Returns the indicated Column Holder Name for the RecordSet,
621         */
622         Field & Column(PString Name);
623         //@}
624 
625       protected:
626         PODBCStmt stmt;      /// ODBC Fetched Statement Info
627         PString tableName;    /// Name of the Fetched Table (if used in Constructor)
628         Row * RowHandler;      /// row Handler
629     };
630 
631     /**@name Data Queries */
632     //@{
633     /** Load a specified Table/Stored Query or
634     General 'SELECT' SQL Query.
635     This function will return a PODBC::Table for
636     further analysis. Do Not Use this Function for
637     any other SQL statements other than SELECT.
638     */
639     Table LoadTable(PString table);
640 
641     /** Added Information to the DataSource. Use this
642     function if you just want to use a SQL statement
643     to add data to a datasource without retreiving the
644     data itself. ie "UPDATE" "APPEND" "INSERT" queries.
645     */
646     PBoolean Query(PString Query);
647     //@}
648 
649 
650     /**@name DataSource Access */
651     //@{
652     /** DataSource
653     This is the main function to call to contact a
654     DataSource. Source specifies the Type of DataSource
655     to contact and the Data parameter contain the relevent
656     connection information. You can choose to call this function
657     or use the specific Connection function.
658     */
659     PBoolean DataSource(DataSources Source, ConnectData Data);
660 
661     /** General Connect Function
662     Custom connection strings should call this
663     to connect Don't ask why its LPCTSTR!
664     */
665     virtual PBoolean Connect(LPCTSTR svSource);
666 
667     /** Connect to IBM DB2 DataSource
668     */
669     PBoolean Connect_DB2(PFilePath DBPath);
670 
671     /** Connect to MS Office excel spreadsheet
672     */
673     PBoolean Connect_XLS(PFilePath XLSPath,PString DefDir = "");
674 
675     /** Connect to an ascii text or cvs file
676     */
677     PBoolean Connect_TXT(PFilePath TXTPath);
678 
679     /** Connect to a Foxpro dataSource
680     */
681     PBoolean Connect_FOX(PFilePath DBPath,PString User = "",
682       PString Pass = "",PString Type= "DBF",
683       PBoolean Exclusive=false);
684 
685     /** Connect to a MS Access *.mdb DataSource.
686     */
687     PBoolean Connect_MDB(PFilePath MDBPath,PString User ="",
688       PString Pass = "",PBoolean Exclusive=false);
689 
690     /** Connect to a paradox database datastore
691     */
692     PBoolean Connect_PDOX(PDirectory DBPath,PDirectory DefaultDir,
693       int version =5);
694 
695     /** Connect to an Oracle Datasource
696     */
697     PBoolean Connect_Oracle(PString Server,PString User="", PString Pass="");
698 
699     /** Connect to a DBase DataStore
700     */
701     PBoolean Connect_DBASE(PDirectory DBPath);
702 
703     /** Connect to a MS SQL Server
704     */
705     PBoolean Connect_MSSQL(PString User="",PString Pass="",
706       PString Host ="(local)",PBoolean Trusted = true,
707       MSSQLProtocols Proto=MSSQLNamedPipes);
708 
709     /** Connect to a mySQL Server
710     */
711     PBoolean Connect_mySQL(PString User="",PString Pass="",
712       PString Host= "localhost",
713       int Port=3306,int Option=0);
714 
715     /** Connect to a mySQL Server's specified DataBase.
716     */
717     PBoolean ConnectDB_mySQL(PString DB,PString User="",
718       PString Pass="",PString Host= "localhost",
719       int Port=3306,int Option=0);
720 
721     /** Connect to a postgreSQL Server
722     */
723     PBoolean Connect_postgreSQL(PString DB,PString User,
724       PString Pass,PString Host, int Port=5432,int Option=0);
725 
726     /** General Disconnect from DataSource.
727     */
728     void Disconnect();
729     //@}
730 
731     /**@name Utilities */
732     //@{
733     /** Retrieve a List of Tables in the Datasource
734     use the option field to specify the type of
735     data to access. ie "TABLE" or "VIEW" (further dev req'd)
736     */
737     PStringArray TableList(PString option = "");
738 
739     /** Check whether their is a limit to Datalength
740     when obtaining Long Data
741     */
742     PBoolean NeedLongDataLen();
743 
744     /** OnSQL Error
745     */
OnSQLError(PString RetCode,PString RetString)746     virtual void OnSQLError(PString RetCode, PString RetString) {};
747 
748 
749     /** Set the Number of Decimal places to
750     round to By Default it is 4. However if the field
751     decimal places is less then Precision Value the
752     field rounding will be used. This must be set prior
753     to calling LoadTable()
754     */
755     void SetPrecision(int Digit);
756 
757     /** Set the Time Display Format
758     */
759     void SetTimeFormat(PTime::TimeFormat tformat);
760 
761     /** Operator Handle DataBase Connection
762     */
HDBC()763     operator HDBC() { return m_hDBC; };
764     //@}
765 
766     PODBC::DataSources  dbase; /// Database Type connected to
767 
768   protected:
769     SQLRETURN       m_nReturn;      // Internal SQL Error code
770     HENV            m_hEnv;         // Handle to environment
771     HDBC            m_hDBC;         // Handle to database connection
772 };
773 
774 
775 /**
776   DSN (Data Source Name) Connection. The connection settings
777   have been preconfiured in the MDAC (Microsoft Data Access Component)
778   and is called using those Preset Settings. Calling the PDSNConnection::Connect
779   has the same effect and is a replaceable for PODBC::DataSource,
780  */
781 class PDSNConnection : public PODBC
782 {
783     PCLASSINFO(PDSNConnection, PODBC);
784 
785   public:
786     /**@name Constructor/Deconstructor */
787     //@{
788     PDSNConnection();
789     ~PDSNConnection();
790     //@}
791 
792     /**@name Connection/Disconnect */
793     //@{
794     /** Connect to the MDAC using a pre-existing MDAC Defined DataSource
795     This is different than calling PODBC::DataSource in that the
796     Data Source is known defined externally within MDAC,
797     */
798     PBoolean Connect( PString Source ,PString Username, PString Password);
799 };
800 
801 
802  //--
803 /** PODBCRecord
804     This Class is used to analyse the fetched data and handles
805     Data Conversion/Read Write operations. It is used in conjuction
806     with the PODBCStmt Class
807 */
808 
809 class PODBCRecord : public PObject
810 {
811     PCLASSINFO(PODBCRecord, PObject);
812 
813   public:
814     /**@name Constructor/Deconstructor */
815     //@{
816     /** Constructor
817     */
818     PODBCRecord(PODBCStmt * hStmt);
819 
820     /** Deconstructor
821     */
~PODBCRecord()822     ~PODBCRecord(){};
823     //@}
824 
825     /**@name Data Collection/Saving */
826     //@{
827     /** Data: Main Call to retrieve and convert Field Data
828     and return the information in the PODBC::Field structure.
829     */
830     void Data(PINDEX Column, PODBC::Field & field);
831 
832     /** InternalGetData is call when retrieving string or large binary
833     data where the size is indetermined. The Function can be iteratively
834     called until the function returns false.
835     */
836     PBoolean InternalGetData(
837       USHORT Column,
838       LPVOID pBuffer,
839       ULONG pBufLen,
840       SQLINTEGER * dataLen=NULL,
841       int Type=SQL_C_DEFAULT
842       );
843 
844     /* Get Long Character Data. Long Data fields cannot be bound
845     and Data must be Got from the RecordSet.
846     */
847     PString GetLongData(PINDEX Column);
848 
849     /** Post the new record back to the RecordSet;
850     */
851     PBoolean PostNew(PODBC::Row & rec);
852 
853     /** Post the Updated record back to the RecordSet;
854     */
855     PBoolean PostUpdate(PODBC::Row & rec);
856 
857     /** Post a Delete command to the RecordSet; Default
858     1 Row is deleted.
859     */
860     PBoolean PostDelete(PINDEX row= 1);
861 
862     /** Check for and Save Long Data
863     */
864     PBoolean InternalSaveLongData(SQLRETURN nRet,PODBC::Row & rec);
865 
866     /** InternalBindColumn for Data input.
867     */
868     PBoolean InternalBindColumn(
869       USHORT Column,LPVOID pBuffer,
870       ULONG pBufferSize,
871       LONG * pReturnedBufferSize=NULL,
872       USHORT nType=SQL_C_TCHAR
873       );
874     //@}
875 
876     /**@name Data Information */
877     //@{
878     /** ColumnByName returns the column number of the column name
879     If not found returns column value of 0;
880     */
881     PINDEX ColumnByName(PString Column);
882 
883     /** ColumnCount No of columns
884     */
885     PINDEX ColumnCount();
886 
887     /** ColumnTypes
888     */
889     PODBC::FieldTypes ColumnType(PINDEX Column );
890 
891     /** Column Size
892     */
893     DWORD ColumnSize( PINDEX Column );
894 
895     /** Column Scale
896     */
897     DWORD ColumnScale( PINDEX Column );
898 
899     /** Column Name
900     */
901     PString ColumnName( PINDEX Column);
902 
903     /** ColumnPrecision Get the Number of Decimal places
904     if Precision is set the precision is set to the
905     lessor of the Two.
906     */
907     unsigned int ColumnPrecision( PINDEX Column );
908 
909     /** IsColumn Nullable. Accepts NULL value
910     */
911     PBoolean IsColumnNullable( PINDEX Column );
912 
913     /** IsColumn Updateable ie is not ReadOnly
914     */
915     PBoolean IsColumnUpdatable( PINDEX Column );
916 
917     /** IsColumnAutoIndex (ie don't give default Value)
918     */
919     PBoolean IsColumnAutoIndex( PINDEX Column );
920 
921     //@}
922 
923     /**@name Data Conversion Settings */
924     //@{
925     /** Conversion Settings
926     */
927     static unsigned int Precision;      /// Double Real Float Decimal digit rounding def= 4;
928     static int MaxCharSize;          /// Long Data Limit KBytes def = 56; (56 Kbytes)
929     static PTime::TimeFormat TimeFormat;/// Time Format
930     //@}
931 
932   protected:
933     HSTMT m_hStmt;
934     PODBCStmt * Stmt;          /// Statement Class
935     PODBC::DataSources dbase;      /// Database Type connecting to
936 
937   friend class PODBC::Field;
938   friend class PODBC::Row;
939 };
940 
941 #endif // P_ODBC
942 
943 #endif // PTLIB_PODBC_H
944 
945 
946 // End Of File ///////////////////////////////////////////////////////////////
947