1 /******************************************************************************
2  * $Id: cpl_odbc.h 657d65d2f09c031221875536844191be01b4ea66 2020-08-31 18:09:29 +1000 Nyall Dawson $
3  *
4  * Project:  OGR ODBC Driver
5  * Purpose:  Declarations for ODBC Access Cover API.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2003, Frank Warmerdam
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #ifndef CPL_ODBC_H_INCLUDED
31 #define CPL_ODBC_H_INCLUDED
32 
33 #include "cpl_port.h"
34 
35 #ifdef WIN32
36 #  include <windows.h>
37 #endif
38 
39 #include <sql.h>
40 #include <sqlext.h>
41 #include <odbcinst.h>
42 #include "cpl_string.h"
43 
44 /*! @cond Doxygen_Suppress */
45 #ifdef PATH_MAX
46 #  define ODBC_FILENAME_MAX PATH_MAX
47 #else
48 #  define ODBC_FILENAME_MAX (255 + 1) /* Max path length */
49 #endif
50 /*! @endcond */
51 
52 /**
53  * \file cpl_odbc.h
54  *
55  * ODBC Abstraction Layer (C++).
56  */
57 
58 /**
59  * A class providing functions to install or remove ODBC driver.
60  */
61 class CPL_DLL CPLODBCDriverInstaller
62 {
63     char m_szPathOut[ODBC_FILENAME_MAX];
64     char m_szError[SQL_MAX_MESSAGE_LENGTH];
65     DWORD m_nErrorCode;
66     DWORD m_nUsageCount;
67 
68   public:
69 
70     // Default constructor.
71     CPLODBCDriverInstaller();
72 
73     /**
74      * Installs ODBC driver or updates definition of already installed driver.
75      * Interanally, it calls ODBC's SQLInstallDriverEx function.
76      *
77      * @param pszDriver - The driver definition as a list of keyword-value
78      * pairs describing the driver (See ODBC API Reference).
79      *
80      * @param pszPathIn - Full path of the target directory of the installation,
81      * or a null pointer (for unixODBC, NULL is passed).
82      *
83      * @param fRequest - The fRequest argument must contain one of
84      * the following values:
85      * ODBC_INSTALL_COMPLETE - (default) complete the installation request
86      * ODBC_INSTALL_INQUIRY - inquire about where a driver can be installed
87      *
88      * @return TRUE indicates success, FALSE if it fails.
89      */
90     int InstallDriver( const char* pszDriver, const char* pszPathIn,
91             WORD fRequest = ODBC_INSTALL_COMPLETE );
92 
93     /**
94      * Removes or changes information about the driver from
95      * the Odbcinst.ini entry in the system information.
96      *
97      * @param pszDriverName - The name of the driver as registered in
98      * the Odbcinst.ini key of the system information.
99      *
100      * @param fRemoveDSN - TRUE: Remove DSNs associated with the driver
101      * specified in lpszDriver. FALSE: Do not remove DSNs associated
102      * with the driver specified in lpszDriver.
103      *
104      * @return The function returns TRUE if it is successful,
105      * FALSE if it fails. If no entry exists in the system information
106      * when this function is called, the function returns FALSE.
107      * In order to obtain usage count value, call GetUsageCount().
108      */
109     int RemoveDriver( const char* pszDriverName, int fRemoveDSN = FALSE );
110 
111     /** The usage count of the driver after this function has been called */
GetUsageCount()112     int GetUsageCount() const {  return m_nUsageCount; }
113 
114     /** Path of the target directory where the driver should be installed.
115      * For details, see ODBC API Reference and lpszPathOut
116      * parameter of SQLInstallDriverEx
117      */
GetPathOut()118     const char* GetPathOut() const { return m_szPathOut; }
119 
120     /** If InstallDriver returns FALSE, then GetLastError then
121      * error message can be obtained by calling this function.
122      * Internally, it calls ODBC's SQLInstallerError function.
123      */
GetLastError()124     const char* GetLastError() const { return m_szError; }
125 
126     /** If InstallDriver returns FALSE, then GetLastErrorCode then
127      * error code can be obtained by calling this function.
128      * Internally, it calls ODBC's SQLInstallerError function.
129      * See ODBC API Reference for possible error flags.
130      */
GetLastErrorCode()131     DWORD GetLastErrorCode() const { return m_nErrorCode; }
132 };
133 
134 class CPLODBCStatement;
135 
136 /* On MSVC SQLULEN is missing in some cases (i.e. VC6)
137 ** but it is always a #define so test this way.   On Unix
138 ** it is a typedef so we can't always do this.
139 */
140 #if defined(_MSC_VER) && !defined(SQLULEN) && !defined(_WIN64)
141 #  define MISSING_SQLULEN
142 #endif
143 
144 /*! @cond Doxygen_Suppress */
145 #if !defined(MISSING_SQLULEN)
146 /* ODBC types to support 64 bit compilation */
147 #  define CPL_SQLULEN SQLULEN
148 #  define CPL_SQLLEN  SQLLEN
149 #else
150 #  define CPL_SQLULEN SQLUINTEGER
151 #  define CPL_SQLLEN  SQLINTEGER
152 #endif  /* ifdef SQLULEN */
153 /*! @endcond */
154 
155 /**
156  * A class representing an ODBC database session.
157  *
158  * Includes error collection services.
159  */
160 
161 class CPL_DLL CPLODBCSession {
162 
CPL_DISALLOW_COPY_ASSIGN(CPLODBCSession)163     CPL_DISALLOW_COPY_ASSIGN(CPLODBCSession)
164 
165     CPLString m_osLastError{};
166     HENV      m_hEnv = nullptr;
167     HDBC      m_hDBC = nullptr;
168     int       m_bInTransaction = false;
169     int       m_bAutoCommit = true;
170 
171   public:
172     CPLODBCSession();
173     ~CPLODBCSession();
174 
175     int         EstablishSession( const char *pszDSN,
176                                   const char *pszUserid,
177                                   const char *pszPassword );
178     const char  *GetLastError();
179 
180     // Transaction handling
181 
182     int         ClearTransaction();
183     int         BeginTransaction();
184     int         CommitTransaction();
185     int         RollbackTransaction();
186     /** Returns whether a transaction is active */
IsInTransaction()187     int         IsInTransaction() { return m_bInTransaction; }
188 
189     // Essentially internal.
190 
191     int         CloseSession();
192 
193     int         Failed( int, HSTMT = nullptr );
194     /** Return connection handle */
GetConnection()195     HDBC        GetConnection() { return m_hDBC; }
196     /** Return GetEnvironment handle */
GetEnvironment()197     HENV        GetEnvironment()  { return m_hEnv; }
198 
199     bool ConnectToMsAccess( const char * pszName, const char* pszDSNStringTemplate );
200 
201 };
202 
203 /**
204  * Abstraction for statement, and resultset.
205  *
206  * Includes methods for executing an SQL statement, and for accessing the
207  * resultset from that statement.  Also provides for executing other ODBC
208  * requests that produce results sets such as SQLColumns() and SQLTables()
209  * requests.
210  */
211 
212 class CPL_DLL CPLODBCStatement {
213 
214     CPL_DISALLOW_COPY_ASSIGN(CPLODBCStatement)
215 
216     CPLODBCSession     *m_poSession = nullptr;
217     HSTMT               m_hStmt = nullptr;
218 
219     SQLSMALLINT    m_nColCount = 0;
220     char         **m_papszColNames = nullptr;
221     SQLSMALLINT   *m_panColType = nullptr;
222     char         **m_papszColTypeNames = nullptr;
223     CPL_SQLULEN      *m_panColSize = nullptr;
224     SQLSMALLINT   *m_panColPrecision = nullptr;
225     SQLSMALLINT   *m_panColNullable = nullptr;
226     char         **m_papszColColumnDef = nullptr;
227 
228     char         **m_papszColValues = nullptr;
229     CPL_SQLLEN       *m_panColValueLengths = nullptr;
230 
231     int            Failed( int );
232 
233     char          *m_pszStatement = nullptr;
234     size_t         m_nStatementMax = 0;
235     size_t         m_nStatementLen = 0;
236 
237   public:
238     explicit CPLODBCStatement( CPLODBCSession * );
239     ~CPLODBCStatement();
240 
241     /** Return statement handle */
GetStatement()242     HSTMT          GetStatement() { return m_hStmt; }
243 
244     // Command buffer related.
245     void           Clear();
246     void           AppendEscaped( const char * );
247     void           Append( const char * );
248     void           Append( int );
249     void           Append( double );
250     int            Appendf( CPL_FORMAT_STRING(const char *), ... ) CPL_PRINT_FUNC_FORMAT (2, 3);
251     /** Return statement string */
GetCommand()252     const char    *GetCommand() { return m_pszStatement; }
253 
254     int            ExecuteSQL( const char * = nullptr );
255 
256     // Results fetching
257     int            Fetch( int nOrientation = SQL_FETCH_NEXT,
258                           int nOffset = 0 );
259     void           ClearColumnData();
260 
261     int            GetColCount();
262     const char    *GetColName( int );
263     short          GetColType( int );
264     const char    *GetColTypeName( int );
265     short          GetColSize( int );
266     short          GetColPrecision( int );
267     short          GetColNullable( int );
268     const char    *GetColColumnDef( int );
269 
270     int            GetColId( const char * );
271     const char    *GetColData( int, const char * = nullptr );
272     const char    *GetColData( const char *, const char * = nullptr );
273     int            GetColDataLength( int );
274     int            GetRowCountAffected();
275 
276     // Fetch special metadata.
277     int            GetColumns( const char *pszTable,
278                                const char *pszCatalog = nullptr,
279                                const char *pszSchema = nullptr );
280     int            GetPrimaryKeys( const char *pszTable,
281                                    const char *pszCatalog = nullptr,
282                                    const char *pszSchema = nullptr );
283 
284     int            GetTables( const char *pszCatalog = nullptr,
285                               const char *pszSchema = nullptr );
286 
287     void           DumpResult( FILE *fp, int bShowSchema = FALSE );
288 
289     static CPLString GetTypeName( int );
290     static SQLSMALLINT GetTypeMapping( SQLSMALLINT );
291 
292     int            CollectResultsInfo();
293 };
294 
295 #endif
296