LCOV - code coverage report
Current view: directory - port - cpl_odbc.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 492 69 14.0 %
Date: 2012-04-28 Functions: 48 8 16.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_odbc.cpp 20862 2010-10-17 15:47:12Z tamas $
       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                 : #include "cpl_odbc.h"
      31                 : #include "cpl_vsi.h"
      32                 : #include "cpl_string.h"
      33                 : #include "cpl_error.h"
      34                 : 
      35                 : 
      36                 : #ifndef WIN32CE /* ODBC is not supported on Windows CE. */
      37                 : 
      38                 : CPL_CVSID("$Id: cpl_odbc.cpp 20862 2010-10-17 15:47:12Z tamas $");
      39                 : 
      40                 : #ifndef SQLColumns_TABLE_CAT 
      41                 : #define SQLColumns_TABLE_CAT 1
      42                 : #define SQLColumns_TABLE_SCHEM 2
      43                 : #define SQLColumns_TABLE_NAME 3
      44                 : #define SQLColumns_COLUMN_NAME 4
      45                 : #define SQLColumns_DATA_TYPE 5
      46                 : #define SQLColumns_TYPE_NAME 6
      47                 : #define SQLColumns_COLUMN_SIZE 7
      48                 : #define SQLColumns_BUFFER_LENGTH 8
      49                 : #define SQLColumns_DECIMAL_DIGITS 9
      50                 : #define SQLColumns_NUM_PREC_RADIX 10
      51                 : #define SQLColumns_NULLABLE 11
      52                 : #define SQLColumns_REMARKS 12
      53                 : #define SQLColumns_COLUMN_DEF 13
      54                 : #define SQLColumns_SQL_DATA_TYPE 14
      55                 : #define SQLColumns_SQL_DATETIME_SUB 15
      56                 : #define SQLColumns_CHAR_OCTET_LENGTH 16
      57                 : #define SQLColumns_ORDINAL_POSITION 17
      58                 : #define SQLColumns_IS_NULLABLE 18
      59                 : #endif /* ndef SQLColumns_TABLE_CAT */
      60                 : 
      61                 : /************************************************************************/
      62                 : /*                           CPLODBCDriverInstaller()                   */
      63                 : /************************************************************************/
      64                 : 
      65               2 : CPLODBCDriverInstaller::CPLODBCDriverInstaller()
      66               2 :     : m_nUsageCount(0)
      67                 : {
      68               2 :     memset( m_szPathOut, '\0', ODBC_FILENAME_MAX );
      69               2 :     memset( m_szError, '\0', SQL_MAX_MESSAGE_LENGTH );
      70               2 : }
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                           InstallDriver()                            */
      74                 : /************************************************************************/
      75                 : 
      76               2 : int CPLODBCDriverInstaller::InstallDriver( const char* pszDriver,
      77                 :         const char* pszPathIn, WORD fRequest )
      78                 : {
      79               2 :     CPLAssert( NULL != pszDriver ); 
      80                 : 
      81                 :     // Try to install driver to system-wide location
      82               2 :     if ( FALSE == SQLInstallDriverEx( pszDriver, NULL, m_szPathOut,
      83                 :                     ODBC_FILENAME_MAX, NULL, fRequest,
      84                 :                     &m_nUsageCount ) )
      85                 :     {
      86               2 :         const WORD nErrorNum = 1; // TODO - a function param?
      87               2 :         RETCODE cRet = SQL_ERROR;
      88                 :         
      89                 :         // Failure is likely related to no write permissions to
      90                 :         // system-wide default location, so try to install to HOME
      91                 :        
      92                 :         static char* pszEnvIni = NULL;
      93               2 :         if (pszEnvIni == NULL)
      94                 :         {
      95                 :             // Read HOME location
      96               2 :             char* pszEnvHome = NULL;
      97               2 :             pszEnvHome = getenv("HOME");
      98                 : 
      99               2 :             CPLAssert( NULL != pszEnvHome );
     100               2 :             CPLDebug( "ODBC", "HOME=%s", pszEnvHome );
     101                 : 
     102                 :             // Set ODBCSYSINI variable pointing to HOME location
     103               2 :             pszEnvIni = (char *)CPLMalloc( strlen(pszEnvHome) + 12 );
     104                 : 
     105               2 :             sprintf( pszEnvIni, "ODBCSYSINI=%s", pszEnvHome );
     106                 :             /* a 'man putenv' shows that we cannot free pszEnvIni */
     107                 :             /* because the pointer is used directly by putenv in old glibc */
     108               2 :             putenv( pszEnvIni );
     109                 : 
     110               2 :             CPLDebug( "ODBC", "%s", pszEnvIni );
     111                 :         }
     112                 : 
     113                 :         // Try to install ODBC driver in new location
     114               2 :         if ( FALSE == SQLInstallDriverEx( pszDriver, NULL, m_szPathOut,
     115                 :                 ODBC_FILENAME_MAX, NULL, fRequest,
     116                 :                 &m_nUsageCount ) )
     117                 :         {
     118                 :             cRet = SQLInstallerError( nErrorNum, &m_nErrorCode,
     119               0 :                             m_szError, SQL_MAX_MESSAGE_LENGTH, NULL );
     120               0 :             CPLAssert( SQL_SUCCESS == cRet || SQL_SUCCESS_WITH_INFO == cRet );
     121                 : 
     122                 :             // FAIL
     123               0 :             return FALSE;
     124                 :         }
     125                 :     }
     126                 : 
     127                 :     // SUCCESS
     128               2 :     return TRUE;
     129                 : }
     130                 : 
     131                 : /************************************************************************/
     132                 : /*                           RemoveDriver()                             */
     133                 : /************************************************************************/
     134                 : 
     135               0 : int CPLODBCDriverInstaller::RemoveDriver( const char* pszDriverName, int fRemoveDSN )
     136                 : {
     137               0 :     CPLAssert( NULL != pszDriverName ); 
     138                 : 
     139               0 :     if ( FALSE == SQLRemoveDriver( pszDriverName, fRemoveDSN, &m_nUsageCount ) )
     140                 :     {
     141               0 :         const WORD nErrorNum = 1; // TODO - a function param?
     142                 : 
     143                 :         // Retrieve error code and message
     144                 :         SQLInstallerError( nErrorNum, &m_nErrorCode,
     145               0 :                            m_szError, SQL_MAX_MESSAGE_LENGTH, NULL );
     146                 : 
     147               0 :         return FALSE;
     148                 :     }
     149                 : 
     150                 :     // SUCCESS
     151               0 :     return TRUE;
     152                 : }
     153                 : 
     154                 : /************************************************************************/
     155                 : /*                           CPLODBCSession()                           */
     156                 : /************************************************************************/
     157                 : 
     158               2 : CPLODBCSession::CPLODBCSession()
     159                 : 
     160                 : {
     161               2 :     m_szLastError[0] = '\0';
     162               2 :     m_hEnv = NULL;
     163               2 :     m_hDBC = NULL;
     164               2 :     m_bInTransaction = FALSE;
     165               2 :     m_bAutoCommit = TRUE;
     166               2 : }
     167                 : 
     168                 : /************************************************************************/
     169                 : /*                          ~CPLODBCSession()                           */
     170                 : /************************************************************************/
     171                 : 
     172               2 : CPLODBCSession::~CPLODBCSession()
     173                 : 
     174                 : {
     175               2 :     CloseSession();
     176               2 : }
     177                 : 
     178                 : /************************************************************************/
     179                 : /*                            CloseSession()                            */
     180                 : /************************************************************************/
     181                 : 
     182               6 : int CPLODBCSession::CloseSession()
     183                 : 
     184                 : {
     185               6 :     if( m_hDBC!=NULL ) 
     186                 :     {
     187               2 :         CPLDebug( "ODBC", "SQLDisconnect()" );
     188               2 :         SQLDisconnect( m_hDBC );
     189               2 :         SQLFreeConnect( m_hDBC );
     190               2 :         m_hDBC = NULL;
     191                 :     }
     192                 :     
     193               6 :     if( m_hEnv!=NULL )
     194                 :     {
     195               2 :         SQLFreeEnv( m_hEnv );
     196               2 :         m_hEnv = NULL;
     197                 :     }
     198                 : 
     199               6 :     return TRUE;
     200                 : }
     201                 : 
     202                 : /************************************************************************/
     203                 : /*                       ClearTransaction()                             */
     204                 : /************************************************************************/
     205                 : 
     206               0 : int CPLODBCSession::ClearTransaction()
     207                 : 
     208                 : {
     209                 : #if (ODBCVER >= 0x0300)
     210                 : 
     211               0 :     if (m_bAutoCommit)
     212               0 :         return TRUE;
     213                 : 
     214                 :     SQLUINTEGER bAutoCommit;
     215                 :     /* See if we already in manual commit mode */
     216               0 :     if ( Failed( SQLGetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, &bAutoCommit, sizeof(SQLUINTEGER), NULL) ) )
     217               0 :         return FALSE;
     218                 : 
     219               0 :     if (bAutoCommit == SQL_AUTOCOMMIT_OFF)
     220                 :     {
     221                 :         /* switch the connection to auto commit mode (default) */
     222               0 :         if( Failed( SQLSetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0 ) ) )
     223               0 :             return FALSE;
     224                 :     }
     225                 : 
     226               0 :     m_bAutoCommit = TRUE;
     227                 : 
     228                 : #endif
     229               0 :     return TRUE;
     230                 : }
     231                 : 
     232                 : /************************************************************************/
     233                 : /*                       CommitTransaction()                            */
     234                 : /************************************************************************/
     235                 : 
     236               0 : int CPLODBCSession::BeginTransaction()
     237                 : 
     238                 : {
     239                 : #if (ODBCVER >= 0x0300)
     240                 : 
     241                 :     SQLUINTEGER bAutoCommit;
     242                 :     /* See if we already in manual commit mode */
     243               0 :     if ( Failed( SQLGetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, &bAutoCommit, sizeof(SQLUINTEGER), NULL) ) )
     244               0 :         return FALSE;
     245                 : 
     246               0 :     if (bAutoCommit == SQL_AUTOCOMMIT_ON)
     247                 :     {
     248                 :         /* switch the connection to manual commit mode */
     249               0 :         if( Failed( SQLSetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0 ) ) )
     250               0 :             return FALSE;
     251                 :     }
     252                 : 
     253               0 :     m_bInTransaction = TRUE;
     254               0 :     m_bAutoCommit = FALSE;
     255                 : 
     256                 : #endif
     257               0 :     return TRUE;
     258                 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                       CommitTransaction()                            */
     262                 : /************************************************************************/
     263                 : 
     264               0 : int CPLODBCSession::CommitTransaction()
     265                 : 
     266                 : {
     267                 : #if (ODBCVER >= 0x0300)
     268                 : 
     269               0 :     if (m_bInTransaction)
     270                 :     {
     271               0 :         if( Failed( SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_COMMIT ) ) )
     272                 :         {
     273               0 :             return FALSE;
     274                 :         }
     275               0 :         m_bInTransaction = FALSE;
     276                 :     }
     277                 : 
     278                 : #endif
     279               0 :     return TRUE;
     280                 : }
     281                 : 
     282                 : /************************************************************************/
     283                 : /*                       RollbackTransaction()                          */
     284                 : /************************************************************************/
     285                 : 
     286               0 : int CPLODBCSession::RollbackTransaction()
     287                 : 
     288                 : {
     289                 : #if (ODBCVER >= 0x0300)
     290                 : 
     291               0 :     if (m_bInTransaction)
     292                 :     {
     293               0 :         m_bInTransaction = FALSE;
     294                 : 
     295               0 :         int nRetCode = SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_ROLLBACK );
     296                 :         
     297               0 :         if( nRetCode != SQL_SUCCESS && nRetCode != SQL_SUCCESS_WITH_INFO )
     298               0 :             return FALSE;
     299                 :     }
     300                 : 
     301                 : #endif
     302               0 :     return TRUE;
     303                 : }
     304                 : 
     305                 : /************************************************************************/
     306                 : /*                               Failed()                               */
     307                 : /*                                                                      */
     308                 : /*      Test if a return code indicates failure, return TRUE if that    */
     309                 : /*      is the case. Also update error text.                            */
     310                 : /************************************************************************/
     311                 : 
     312               6 : int CPLODBCSession::Failed( int nRetCode, HSTMT hStmt )
     313                 : 
     314                 : {
     315                 :     SQLCHAR achSQLState[SQL_MAX_MESSAGE_LENGTH];
     316                 :     SQLINTEGER nNativeError;
     317               6 :     SQLSMALLINT nTextLength=0;
     318                 : 
     319               6 :     m_szLastError[0] = '\0';
     320                 : 
     321               6 :     if( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
     322               4 :         return FALSE;
     323                 : 
     324                 :     SQLError( m_hEnv, m_hDBC, hStmt, achSQLState, &nNativeError,
     325                 :               (SQLCHAR *) m_szLastError, sizeof(m_szLastError)-1, 
     326               2 :               &nTextLength );
     327               2 :     m_szLastError[nTextLength] = '\0';
     328                 : 
     329               2 :     if( nRetCode == SQL_ERROR && m_bInTransaction )
     330               0 :         RollbackTransaction();
     331                 : 
     332               2 :     return TRUE;
     333                 : }
     334                 : 
     335                 : /************************************************************************/
     336                 : /*                          EstablishSession()                          */
     337                 : /************************************************************************/
     338                 : 
     339                 : /**
     340                 :  * Connect to database and logon.
     341                 :  *
     342                 :  * @param pszDSN The name of the DSN being used to connect.  This is not
     343                 :  * optional.
     344                 :  *
     345                 :  * @param pszUserid the userid to logon as, may be NULL if not not required,
     346                 :  * or provided by the DSN. 
     347                 :  *
     348                 :  * @param pszPassword the password to logon with.   May be NULL if not required
     349                 :  * or provided by the DSN.
     350                 :  *
     351                 :  * @return TRUE on success or FALSE on failure.  Call GetLastError() to get
     352                 :  * details on failure. 
     353                 :  */
     354                 : 
     355               2 : int CPLODBCSession::EstablishSession( const char *pszDSN, 
     356                 :                                       const char *pszUserid, 
     357                 :                                       const char *pszPassword )
     358                 : 
     359                 : {
     360               2 :     CloseSession();
     361                 :     
     362               2 :     if( Failed( SQLAllocEnv( &m_hEnv ) ) )
     363               0 :         return FALSE;
     364                 : 
     365               2 :     if( Failed( SQLAllocConnect( m_hEnv, &m_hDBC ) ) )
     366                 :     {
     367               0 :         CloseSession();
     368               0 :         return FALSE;
     369                 :     }
     370                 : 
     371               2 :     SQLSetConnectOption( m_hDBC,SQL_LOGIN_TIMEOUT,30 );
     372                 : 
     373               2 :     if( pszUserid == NULL )
     374               2 :         pszUserid = "";
     375               2 :     if( pszPassword == NULL )
     376               2 :         pszPassword = "";
     377                 : 
     378                 :     int bFailed;
     379               2 :     if( strstr(pszDSN,"=") != NULL )
     380                 :     {
     381                 :         SQLCHAR szOutConnString[1024];
     382               2 :         SQLSMALLINT nOutConnStringLen = 0;
     383                 : 
     384               2 :         CPLDebug( "ODBC", "SQLDriverConnect(%s)", pszDSN );
     385                 :         bFailed = Failed(
     386                 :             SQLDriverConnect( m_hDBC, NULL, 
     387                 :                               (SQLCHAR *) pszDSN, (SQLSMALLINT)strlen(pszDSN), 
     388                 :                               szOutConnString, sizeof(szOutConnString), 
     389               2 :                               &nOutConnStringLen, SQL_DRIVER_NOPROMPT ) );
     390                 :     }
     391                 :     else
     392                 :     {
     393               0 :         CPLDebug( "ODBC", "SQLConnect(%s)", pszDSN );
     394                 :         bFailed = Failed(
     395                 :             SQLConnect( m_hDBC, (SQLCHAR *) pszDSN, SQL_NTS, 
     396                 :                         (SQLCHAR *) pszUserid, SQL_NTS, 
     397               0 :                         (SQLCHAR *) pszPassword, SQL_NTS ) );
     398                 :     }
     399                 : 
     400               2 :     if( bFailed )
     401                 :     {
     402               2 :         CPLDebug( "ODBC", "... failed: %s", GetLastError() );
     403               2 :         CloseSession();
     404               2 :         return FALSE;
     405                 :     }
     406                 : 
     407               0 :     return TRUE;
     408                 : }
     409                 : 
     410                 : /************************************************************************/
     411                 : /*                            GetLastError()                            */
     412                 : /************************************************************************/
     413                 : 
     414                 : /**
     415                 :  * Returns the last ODBC error message.
     416                 :  *
     417                 :  * @return pointer to an internal buffer with the error message in it. 
     418                 :  * Do not free or alter.  Will be an empty (but not NULL) string if there is
     419                 :  * no pending error info.
     420                 :  */
     421                 : 
     422               4 : const char *CPLODBCSession::GetLastError()
     423                 : 
     424                 : {
     425               4 :     return m_szLastError;
     426                 : }
     427                 : 
     428                 : /************************************************************************/
     429                 : /* ==================================================================== */
     430                 : /*                           CPLODBCStatement                           */
     431                 : /* ==================================================================== */
     432                 : /************************************************************************/
     433                 : 
     434                 : /************************************************************************/
     435                 : /*                          CPLODBCStatement()                          */
     436                 : /************************************************************************/
     437                 : 
     438               0 : CPLODBCStatement::CPLODBCStatement( CPLODBCSession *poSession )
     439                 : 
     440                 : {
     441               0 :     m_poSession = poSession;
     442                 : 
     443               0 :     if( Failed( 
     444                 :             SQLAllocStmt( poSession->GetConnection(), &m_hStmt ) ) )
     445                 :     {
     446               0 :         m_hStmt = NULL;
     447               0 :         return;
     448                 :     }
     449                 : 
     450               0 :     m_nColCount = 0;
     451               0 :     m_papszColNames = NULL;
     452               0 :     m_panColType = NULL;
     453               0 :     m_papszColTypeNames = NULL;
     454               0 :     m_panColSize = NULL;
     455               0 :     m_panColPrecision = NULL;
     456               0 :     m_panColNullable = NULL;
     457                 : 
     458               0 :     m_papszColValues = NULL;
     459               0 :     m_panColValueLengths = NULL;
     460                 : 
     461               0 :     m_pszStatement = NULL;
     462               0 :     m_nStatementMax = 0;
     463               0 :     m_nStatementLen = 0;
     464                 : }
     465                 : 
     466                 : /************************************************************************/
     467                 : /*                         ~CPLODBCStatement()                          */
     468                 : /************************************************************************/
     469                 : 
     470               0 : CPLODBCStatement::~CPLODBCStatement()
     471                 : 
     472                 : {
     473               0 :     Clear();
     474                 : 
     475               0 :     if( m_hStmt != NULL )
     476               0 :         SQLFreeStmt( m_hStmt, SQL_DROP );
     477               0 : }
     478                 : 
     479                 : /************************************************************************/
     480                 : /*                             ExecuteSQL()                             */
     481                 : /************************************************************************/
     482                 : 
     483                 : /**
     484                 :  * Execute an SQL statement.
     485                 :  *
     486                 :  * This method will execute the passed (or stored) SQL statement, 
     487                 :  * and initialize information about the resultset if there is one. 
     488                 :  * If a NULL statement is passed, the internal stored statement that
     489                 :  * has been previously set via Append() or Appendf() calls will be used. 
     490                 :  *
     491                 :  * @param pszStatement the SQL statement to execute, or NULL if the
     492                 :  * internally saved one should be used. 
     493                 :  *
     494                 :  * @return TRUE on success or FALSE if there is an error.  Error details
     495                 :  * can be fetched with OGRODBCSession::GetLastError().
     496                 :  */
     497                 : 
     498               0 : int CPLODBCStatement::ExecuteSQL( const char *pszStatement )
     499                 : 
     500                 : {
     501               0 :     if( m_poSession == NULL || m_hStmt == NULL )
     502                 :     {
     503                 :         // we should post an error.
     504               0 :         return FALSE;
     505                 :     }
     506                 : 
     507               0 :     if( pszStatement != NULL )
     508                 :     {
     509               0 :         Clear();
     510               0 :         Append( pszStatement );
     511                 :     }
     512                 : 
     513                 : #if (ODBCVER >= 0x0300)
     514                 : 
     515               0 :     if ( !m_poSession->IsInTransaction() )
     516                 :     {
     517                 :         /* commit pending transactions and set to autocommit mode*/
     518               0 :         m_poSession->ClearTransaction();
     519                 :     }
     520                 : 
     521                 : #endif
     522                 : 
     523               0 :     if( Failed( 
     524                 :             SQLExecDirect( m_hStmt, (SQLCHAR *) m_pszStatement, SQL_NTS ) ) )
     525               0 :         return FALSE;
     526                 : 
     527               0 :     return CollectResultsInfo();
     528                 : }
     529                 : 
     530                 : /************************************************************************/
     531                 : /*                         CollectResultsInfo()                         */
     532                 : /************************************************************************/
     533                 : 
     534               0 : int CPLODBCStatement::CollectResultsInfo()
     535                 : 
     536                 : {
     537               0 :     if( m_poSession == NULL || m_hStmt == NULL )
     538                 :     {
     539                 :         // we should post an error.
     540               0 :         return FALSE;
     541                 :     }
     542                 : 
     543               0 :     if( Failed( SQLNumResultCols(m_hStmt,&m_nColCount) ) )
     544               0 :         return FALSE;
     545                 : 
     546                 : /* -------------------------------------------------------------------- */
     547                 : /*      Allocate per column information.                                */
     548                 : /* -------------------------------------------------------------------- */
     549               0 :     m_papszColNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
     550               0 :     m_papszColValues = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
     551               0 :     m_panColValueLengths = (_SQLLEN *) CPLCalloc(sizeof(_SQLLEN),(m_nColCount+1));
     552                 : 
     553               0 :     m_panColType = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
     554               0 :     m_papszColTypeNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
     555               0 :     m_panColSize = (_SQLULEN *) CPLCalloc(sizeof(_SQLULEN),m_nColCount);
     556               0 :     m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
     557               0 :     m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
     558                 : 
     559                 : /* -------------------------------------------------------------------- */
     560                 : /*      Fetch column descriptions.                                      */
     561                 : /* -------------------------------------------------------------------- */
     562               0 :     for( SQLUSMALLINT iCol = 0; iCol < m_nColCount; iCol++ )
     563                 :     {
     564                 :         SQLCHAR     szName[256];
     565               0 :         SQLSMALLINT nNameLength = 0;
     566                 : 
     567               0 :         if ( Failed( SQLDescribeCol(m_hStmt, iCol+1, 
     568                 :                                     szName, sizeof(szName), &nNameLength,
     569                 :                                     m_panColType + iCol,
     570                 :                                     m_panColSize + iCol,
     571                 :                                     m_panColPrecision + iCol,
     572                 :                                     m_panColNullable + iCol) ) )
     573               0 :             return FALSE;
     574                 : 
     575               0 :         szName[nNameLength] = '\0';  // Paranoid; the string should be
     576                 :                                       // null-terminated by the driver
     577               0 :         m_papszColNames[iCol] = CPLStrdup((const char*)szName);
     578                 : 
     579                 :         // SQLDescribeCol() fetches just a subset of column attributes.
     580                 :         // In addition to above data we need data type name.
     581               0 :         if ( Failed( SQLColAttribute(m_hStmt, iCol + 1, SQL_DESC_TYPE_NAME,
     582                 :                                      szName, sizeof(szName),
     583                 :                                      &nNameLength, NULL) ) )
     584               0 :             return FALSE;
     585                 : 
     586               0 :         szName[nNameLength] = '\0';  // Paranoid
     587               0 :         m_papszColTypeNames[iCol] = CPLStrdup((const char*)szName);
     588                 : 
     589                 : //        CPLDebug( "ODBC", "%s %s %d", m_papszColNames[iCol], 
     590                 : //                  szName, m_panColType[iCol] );
     591                 :     }
     592                 : 
     593               0 :     return TRUE;
     594                 : }
     595                 : 
     596                 : /************************************************************************/
     597                 : /*                            GetColCount()                             */
     598                 : /************************************************************************/
     599                 : 
     600                 : /**
     601                 :  * Fetch the resultset column count. 
     602                 :  *
     603                 :  * @return the column count, or zero if there is no resultset.
     604                 :  */
     605                 : 
     606               0 : int CPLODBCStatement::GetColCount()
     607                 : 
     608                 : {
     609               0 :     return m_nColCount;
     610                 : }
     611                 : 
     612                 : /************************************************************************/
     613                 : /*                             GetColName()                             */
     614                 : /************************************************************************/
     615                 : 
     616                 : /**
     617                 :  * Fetch a column name.
     618                 :  *
     619                 :  * @param iCol the zero based column index.
     620                 :  *
     621                 :  * @return NULL on failure (out of bounds column), or a pointer to an
     622                 :  * internal copy of the column name. 
     623                 :  */
     624                 : 
     625               0 : const char *CPLODBCStatement::GetColName( int iCol )
     626                 : 
     627                 : {
     628               0 :     if( iCol < 0 || iCol >= m_nColCount )
     629               0 :         return NULL;
     630                 :     else
     631               0 :         return m_papszColNames[iCol];
     632                 : }
     633                 : 
     634                 : /************************************************************************/
     635                 : /*                             GetColType()                             */
     636                 : /************************************************************************/
     637                 : 
     638                 : /**
     639                 :  * Fetch a column data type.
     640                 :  *
     641                 :  * The return type code is a an ODBC SQL_ code, one of SQL_UNKNOWN_TYPE, 
     642                 :  * SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT,
     643                 :  * SQL_REAL, SQL_DOUBLE, SQL_DATETIME, SQL_VARCHAR, SQL_TYPE_DATE, 
     644                 :  * SQL_TYPE_TIME, SQL_TYPE_TIMESTAMPT.
     645                 :  *
     646                 :  * @param iCol the zero based column index.
     647                 :  *
     648                 :  * @return type code or -1 if the column is illegal.
     649                 :  */
     650                 : 
     651               0 : short CPLODBCStatement::GetColType( int iCol )
     652                 : 
     653                 : {
     654               0 :     if( iCol < 0 || iCol >= m_nColCount )
     655               0 :         return -1;
     656                 :     else
     657               0 :         return m_panColType[iCol];
     658                 : }
     659                 : 
     660                 : /************************************************************************/
     661                 : /*                             GetColTypeName()                         */
     662                 : /************************************************************************/
     663                 : 
     664                 : /**
     665                 :  * Fetch a column data type name.
     666                 :  *
     667                 :  * Returns data source-dependent data type name; for example, "CHAR",
     668                 :  * "VARCHAR", "MONEY", "LONG VARBINAR", or "CHAR ( ) FOR BIT DATA".
     669                 :  *
     670                 :  * @param iCol the zero based column index.
     671                 :  *
     672                 :  * @return NULL on failure (out of bounds column), or a pointer to an
     673                 :  * internal copy of the column dat type name.
     674                 :  */
     675                 : 
     676               0 : const char *CPLODBCStatement::GetColTypeName( int iCol )
     677                 : 
     678                 : {
     679               0 :     if( iCol < 0 || iCol >= m_nColCount )
     680               0 :         return NULL;
     681                 :     else
     682               0 :         return m_papszColTypeNames[iCol];
     683                 : }
     684                 : 
     685                 : /************************************************************************/
     686                 : /*                             GetColSize()                             */
     687                 : /************************************************************************/
     688                 : 
     689                 : /**
     690                 :  * Fetch the column width.
     691                 :  *
     692                 :  * @param iCol the zero based column index.
     693                 :  *
     694                 :  * @return column width, zero for unknown width columns.
     695                 :  */
     696                 : 
     697               0 : short CPLODBCStatement::GetColSize( int iCol )
     698                 : 
     699                 : {
     700               0 :     if( iCol < 0 || iCol >= m_nColCount )
     701               0 :         return -1;
     702                 :     else
     703               0 :         return (short) m_panColSize[iCol];
     704                 : }
     705                 : 
     706                 : /************************************************************************/
     707                 : /*                          GetColPrecision()                           */
     708                 : /************************************************************************/
     709                 : 
     710                 : /**
     711                 :  * Fetch the column precision.
     712                 :  *
     713                 :  * @param iCol the zero based column index.
     714                 :  *
     715                 :  * @return column precision, may be zero or the same as column size for
     716                 :  * columns to which it does not apply. 
     717                 :  */
     718                 : 
     719               0 : short CPLODBCStatement::GetColPrecision( int iCol )
     720                 : 
     721                 : {
     722               0 :     if( iCol < 0 || iCol >= m_nColCount )
     723               0 :         return -1;
     724                 :     else
     725               0 :         return m_panColPrecision[iCol];
     726                 : }
     727                 : 
     728                 : /************************************************************************/
     729                 : /*                           GetColNullable()                           */
     730                 : /************************************************************************/
     731                 : 
     732                 : /**
     733                 :  * Fetch the column nullability.
     734                 :  *
     735                 :  * @param iCol the zero based column index.
     736                 :  *
     737                 :  * @return TRUE if the column may contains or FALSE otherwise.
     738                 :  */
     739                 : 
     740               0 : short CPLODBCStatement::GetColNullable( int iCol )
     741                 : 
     742                 : {
     743               0 :     if( iCol < 0 || iCol >= m_nColCount )
     744               0 :         return -1;
     745                 :     else
     746               0 :         return m_panColNullable[iCol];
     747                 : }
     748                 : 
     749                 : /************************************************************************/
     750                 : /*                               Fetch()                                */
     751                 : /************************************************************************/
     752                 : 
     753                 : /**
     754                 :  * Fetch a new record.
     755                 :  *
     756                 :  * Requests the next row in the current resultset using the SQLFetchScroll()
     757                 :  * call.  Note that many ODBC drivers only support the default forward
     758                 :  * fetching one record at a time.  Only SQL_FETCH_NEXT (the default) should
     759                 :  * be considered reliable on all drivers. 
     760                 :  *
     761                 :  * Currently it isn't clear how to determine whether an error or a normal
     762                 :  * out of data condition has occured if Fetch() fails. 
     763                 :  *
     764                 :  * @param nOrientation One of SQL_FETCH_NEXT, SQL_FETCH_LAST, SQL_FETCH_PRIOR,
     765                 :  * SQL_FETCH_ABSOLUTE, or SQL_FETCH_RELATIVE (default is SQL_FETCH_NEXT).
     766                 :  *
     767                 :  * @param nOffset the offset (number of records), ignored for some 
     768                 :  * orientations.  
     769                 :  *
     770                 :  * @return TRUE if a new row is successfully fetched, or FALSE if not.
     771                 :  */
     772                 : 
     773               0 : int CPLODBCStatement::Fetch( int nOrientation, int nOffset )
     774                 : 
     775                 : {
     776               0 :     ClearColumnData();
     777                 : 
     778               0 :     if( m_hStmt == NULL || m_nColCount < 1 )
     779               0 :         return FALSE;
     780                 : 
     781                 : /* -------------------------------------------------------------------- */
     782                 : /*      Fetch a new row.  Note that some brain dead drives (such as     */
     783                 : /*      the unixodbc text file driver) don't implement                  */
     784                 : /*      SQLScrollFetch(), so we try to stick to SQLFetch() if we        */
     785                 : /*      can).                                                           */
     786                 : /* -------------------------------------------------------------------- */
     787                 :     SQLRETURN nRetCode;
     788                 : 
     789               0 :     if( nOrientation == SQL_FETCH_NEXT && nOffset == 0 )
     790                 :     {
     791               0 :         nRetCode = SQLFetch( m_hStmt );
     792               0 :         if( Failed(nRetCode) )
     793                 :         {
     794               0 :             if ( nRetCode != SQL_NO_DATA )
     795                 :             {
     796                 :                 CPLError( CE_Failure, CPLE_AppDefined, "%s",
     797               0 :                           m_poSession->GetLastError() );
     798                 :             }
     799               0 :             return FALSE;
     800                 :         }
     801                 :     }
     802                 :     else
     803                 :     {
     804               0 :         nRetCode = SQLFetchScroll(m_hStmt, (SQLSMALLINT) nOrientation, nOffset);
     805               0 :         if( Failed(nRetCode) )
     806                 :         {
     807               0 :             if ( nRetCode == SQL_NO_DATA )
     808                 :             {
     809                 :                 CPLError( CE_Failure, CPLE_AppDefined, "%s",
     810               0 :                           m_poSession->GetLastError() );
     811                 :             }
     812               0 :             return FALSE;
     813                 :         }
     814                 :     }
     815                 : 
     816                 : /* -------------------------------------------------------------------- */
     817                 : /*      Pull out all the column values.                                 */
     818                 : /* -------------------------------------------------------------------- */
     819                 :     SQLSMALLINT iCol;
     820                 :     
     821               0 :     for( iCol = 0; iCol < m_nColCount; iCol++ )
     822                 :     {
     823                 :         char szWrkData[513];
     824                 :         _SQLLEN cbDataLen;
     825               0 :         SQLSMALLINT nFetchType = GetTypeMapping( m_panColType[iCol] );
     826                 : 
     827                 :         // Handle values other than WCHAR and BINARY as CHAR.
     828               0 :         if( nFetchType != SQL_C_BINARY && nFetchType != SQL_C_WCHAR )
     829               0 :             nFetchType = SQL_C_CHAR;
     830                 : 
     831               0 :         szWrkData[0] = '\0';
     832               0 :         szWrkData[sizeof(szWrkData)-1] = '\0';
     833                 : 
     834                 :         nRetCode = SQLGetData( m_hStmt, iCol + 1, nFetchType,
     835                 :                                szWrkData, sizeof(szWrkData)-1, 
     836               0 :                                &cbDataLen );
     837                 : 
     838                 : /* SQLGetData() is giving garbage values in the first 4 bytes of cbDataLen *
     839                 :  * in some architectures. Converting it to (int) discards the unnecessary  *
     840                 :  * bytes. This should not be a problem unless the buffer size reaches      *
     841                 :  * 2GB. (#3385)                                                            */
     842               0 :         cbDataLen = (int) cbDataLen;
     843                 : 
     844               0 :         if( Failed( nRetCode ) )
     845                 :         {
     846               0 :             if ( nRetCode == SQL_NO_DATA )
     847                 :             {
     848                 :                 CPLError( CE_Failure, CPLE_AppDefined, "%s",
     849               0 :                           m_poSession->GetLastError() );
     850                 :             }
     851               0 :             return FALSE;
     852                 :         }
     853                 : 
     854               0 :         if( cbDataLen == SQL_NULL_DATA )
     855                 :         {
     856               0 :             m_papszColValues[iCol] = NULL;
     857               0 :             m_panColValueLengths[iCol] = 0;
     858                 :         }
     859                 : 
     860                 :         // assume big result: should check for state=SQLSATE 01004.
     861               0 :         else if( nRetCode == SQL_SUCCESS_WITH_INFO  ) 
     862                 :         {
     863               0 :             if( cbDataLen >= (_SQLLEN)(sizeof(szWrkData)-1) )
     864                 :             {
     865               0 :                 cbDataLen = (_SQLLEN)(sizeof(szWrkData)-1);
     866               0 :                 if (nFetchType == SQL_C_CHAR) 
     867               0 :                     while ((cbDataLen > 1) && (szWrkData[cbDataLen - 1] == 0)) 
     868               0 :                         --cbDataLen; // trimming the extra terminators: bug 990
     869               0 :                 else if (nFetchType == SQL_C_WCHAR)
     870               0 :                     while ((cbDataLen > 1) && (szWrkData[cbDataLen - 1] == 0)
     871               0 :                         && (szWrkData[cbDataLen - 2] == 0)) 
     872               0 :                         cbDataLen -= 2; // trimming the extra terminators
     873                 : 
     874                 :             }
     875                 :       
     876               0 :             m_papszColValues[iCol] = (char *) CPLMalloc(cbDataLen+2);
     877               0 :             memcpy( m_papszColValues[iCol], szWrkData, cbDataLen );
     878               0 :             m_papszColValues[iCol][cbDataLen] = '\0';
     879               0 :             m_papszColValues[iCol][cbDataLen+1] = '\0';
     880               0 :             m_panColValueLengths[iCol] = cbDataLen;
     881                 : 
     882               0 :             while( TRUE )
     883                 :             {
     884                 :                 _SQLLEN nChunkLen;
     885                 : 
     886                 :                 nRetCode = SQLGetData( m_hStmt, (SQLUSMALLINT) iCol+1, 
     887                 :                                        nFetchType,
     888                 :                                        szWrkData, sizeof(szWrkData)-1, 
     889               0 :                                        &cbDataLen );
     890               0 :                 if( nRetCode == SQL_NO_DATA )
     891                 :                     break;
     892                 : 
     893               0 :                 if( Failed( nRetCode ) )
     894                 :                 {
     895                 :                     CPLError( CE_Failure, CPLE_AppDefined, "%s",
     896               0 :                               m_poSession->GetLastError() );
     897               0 :                     return FALSE;
     898                 :                 }
     899                 : 
     900               0 :                 if( cbDataLen >= (int) (sizeof(szWrkData) - 1)
     901                 :                     || cbDataLen == SQL_NO_TOTAL )
     902                 :                 {
     903               0 :                     nChunkLen = sizeof(szWrkData)-1;
     904               0 :                     if (nFetchType == SQL_C_CHAR) 
     905               0 :                         while ( (nChunkLen > 1)
     906               0 :                                 && (szWrkData[nChunkLen - 1] == 0) )
     907               0 :                             --nChunkLen;  // trimming the extra terminators
     908               0 :                     else if (nFetchType == SQL_C_WCHAR)
     909               0 :                         while ( (nChunkLen > 1)
     910               0 :                                 && (szWrkData[nChunkLen - 1] == 0)
     911               0 :                                 && (szWrkData[nChunkLen - 2] == 0) )
     912               0 :                             nChunkLen -= 2;  // trimming the extra terminators
     913                 :                 }
     914                 :                 else
     915               0 :                     nChunkLen = cbDataLen;
     916               0 :                 szWrkData[nChunkLen] = '\0';
     917                 : 
     918               0 :                 m_papszColValues[iCol] = (char *) 
     919               0 :                     CPLRealloc( m_papszColValues[iCol], 
     920               0 :                                 m_panColValueLengths[iCol] + nChunkLen + 2 );
     921               0 :                 memcpy( m_papszColValues[iCol] + m_panColValueLengths[iCol], 
     922               0 :                         szWrkData, nChunkLen );
     923               0 :                 m_panColValueLengths[iCol] += nChunkLen;
     924               0 :                 m_papszColValues[iCol][m_panColValueLengths[iCol]] = '\0';
     925               0 :                 m_papszColValues[iCol][m_panColValueLengths[iCol]+1] = '\0';
     926                 :             }
     927                 :         }
     928                 :         else
     929                 :         {
     930               0 :             m_panColValueLengths[iCol] = cbDataLen;
     931               0 :             m_papszColValues[iCol] = (char *) CPLMalloc(cbDataLen+2);
     932               0 :             memcpy( m_papszColValues[iCol], szWrkData, cbDataLen );
     933               0 :             m_papszColValues[iCol][cbDataLen] = '\0';
     934               0 :             m_papszColValues[iCol][cbDataLen+1] = '\0';
     935                 :         }
     936                 : 
     937                 :         // Trim white space off end, if there is any.
     938               0 :         if( nFetchType == SQL_C_CHAR && m_papszColValues[iCol] != NULL )
     939                 :         {
     940               0 :             char *pszTarget = m_papszColValues[iCol];
     941               0 :             size_t iEnd = strlen(pszTarget);
     942                 : 
     943               0 :             while ( iEnd > 0 && pszTarget[iEnd - 1] == ' ' )
     944               0 :                 pszTarget[--iEnd] = '\0';
     945                 :         }
     946                 : 
     947                 :         // Convert WCHAR to UTF-8, assuming the WCHAR is UCS-2.
     948               0 :         if( nFetchType == SQL_C_WCHAR && m_papszColValues[iCol] != NULL 
     949               0 :             && m_panColValueLengths[iCol] > 0 )
     950                 :         {
     951               0 :             wchar_t *pwszSrc = (wchar_t *) m_papszColValues[iCol];
     952                 : 
     953               0 :             m_papszColValues[iCol] = 
     954               0 :                 CPLRecodeFromWChar( pwszSrc, CPL_ENC_UCS2, CPL_ENC_UTF8 );
     955               0 :             m_panColValueLengths[iCol] = strlen(m_papszColValues[iCol]);
     956                 : 
     957               0 :             CPLFree( pwszSrc );
     958                 :         }
     959                 :     }
     960                 : 
     961               0 :     return TRUE;
     962                 : }
     963                 : 
     964                 : /************************************************************************/
     965                 : /*                             GetColData()                             */
     966                 : /************************************************************************/
     967                 : 
     968                 : /**
     969                 :  * Fetch column data. 
     970                 :  *
     971                 :  * Fetches the data contents of the requested column for the currently loaded
     972                 :  * row.  The result is returned as a string regardless of the column type.  
     973                 :  * NULL is returned if an illegal column is given, or if the actual column
     974                 :  * is "NULL". 
     975                 :  * 
     976                 :  * @param iCol the zero based column to fetch. 
     977                 :  *
     978                 :  * @param pszDefault the value to return if the column does not exist, or is
     979                 :  * NULL.  Defaults to NULL.
     980                 :  *
     981                 :  * @return pointer to internal column data or NULL on failure.
     982                 :  */
     983                 : 
     984               0 : const char *CPLODBCStatement::GetColData( int iCol, const char *pszDefault )
     985                 : 
     986                 : {
     987               0 :     if( iCol < 0 || iCol >= m_nColCount )
     988               0 :         return pszDefault;
     989               0 :     else if( m_papszColValues[iCol] != NULL )
     990               0 :         return m_papszColValues[iCol];
     991                 :     else
     992               0 :         return pszDefault;
     993                 : }
     994                 : 
     995                 : /************************************************************************/
     996                 : /*                             GetColData()                             */
     997                 : /************************************************************************/
     998                 : 
     999                 : /**
    1000                 :  * Fetch column data. 
    1001                 :  *
    1002                 :  * Fetches the data contents of the requested column for the currently loaded
    1003                 :  * row.  The result is returned as a string regardless of the column type.  
    1004                 :  * NULL is returned if an illegal column is given, or if the actual column
    1005                 :  * is "NULL". 
    1006                 :  * 
    1007                 :  * @param pszColName the name of the column requested.
    1008                 :  *
    1009                 :  * @param pszDefault the value to return if the column does not exist, or is
    1010                 :  * NULL.  Defaults to NULL.
    1011                 :  *
    1012                 :  * @return pointer to internal column data or NULL on failure.
    1013                 :  */
    1014                 : 
    1015               0 : const char *CPLODBCStatement::GetColData( const char *pszColName, 
    1016                 :                                           const char *pszDefault )
    1017                 : 
    1018                 : {
    1019               0 :     int iCol = GetColId( pszColName );
    1020                 : 
    1021               0 :     if( iCol == -1 )
    1022               0 :         return pszDefault;
    1023                 :     else
    1024               0 :         return GetColData( iCol, pszDefault );
    1025                 : }
    1026                 : 
    1027                 : /************************************************************************/
    1028                 : /*                          GetColDataLength()                          */
    1029                 : /************************************************************************/
    1030                 : 
    1031               0 : int CPLODBCStatement::GetColDataLength( int iCol )
    1032                 : 
    1033                 : {
    1034               0 :     if( iCol < 0 || iCol >= m_nColCount )
    1035               0 :         return 0;
    1036               0 :     else if( m_papszColValues[iCol] != NULL )
    1037               0 :         return (int)m_panColValueLengths[iCol];
    1038                 :     else
    1039               0 :         return 0;
    1040                 : }
    1041                 : 
    1042                 : /************************************************************************/
    1043                 : /*                              GetColId()                              */
    1044                 : /************************************************************************/
    1045                 : 
    1046                 : /**
    1047                 :  * Fetch column index.
    1048                 :  *
    1049                 :  * Gets the column index corresponding with the passed name.  The
    1050                 :  * name comparisons are case insensitive. 
    1051                 :  *
    1052                 :  * @param pszColName the name to search for. 
    1053                 :  *
    1054                 :  * @return the column index, or -1 if not found.
    1055                 :  */
    1056                 : 
    1057               0 : int CPLODBCStatement::GetColId( const char *pszColName )
    1058                 : 
    1059                 : {
    1060               0 :     for( SQLSMALLINT iCol = 0; iCol < m_nColCount; iCol++ )
    1061               0 :         if( EQUAL(pszColName, m_papszColNames[iCol]) )
    1062               0 :             return iCol;
    1063                 :     
    1064               0 :     return -1;
    1065                 : }
    1066                 : 
    1067                 : /************************************************************************/
    1068                 : /*                          ClearColumnData()                           */
    1069                 : /************************************************************************/
    1070                 : 
    1071               0 : void CPLODBCStatement::ClearColumnData()
    1072                 : 
    1073                 : {
    1074               0 :     if( m_nColCount > 0 )
    1075                 :     {
    1076               0 :         for( int iCol = 0; iCol < m_nColCount; iCol++ )
    1077                 :         {
    1078               0 :             if( m_papszColValues[iCol] != NULL )
    1079                 :             {
    1080               0 :                 CPLFree( m_papszColValues[iCol] );
    1081               0 :                 m_papszColValues[iCol] = NULL;
    1082                 :             }
    1083                 :         }
    1084                 :     }
    1085               0 : }
    1086                 : 
    1087                 : /************************************************************************/
    1088                 : /*                               Failed()                               */
    1089                 : /************************************************************************/
    1090                 : 
    1091               0 : int CPLODBCStatement::Failed( int nResultCode )
    1092                 : 
    1093                 : {
    1094               0 :     if( m_poSession != NULL )
    1095               0 :         return m_poSession->Failed( nResultCode, m_hStmt );
    1096                 : 
    1097               0 :     return TRUE;
    1098                 : }
    1099                 : 
    1100                 : /************************************************************************/
    1101                 : /*                         Append(const char *)                         */
    1102                 : /************************************************************************/
    1103                 : 
    1104                 : /**
    1105                 :  * Append text to internal command.
    1106                 :  *
    1107                 :  * The passed text is appended to the internal SQL command text. 
    1108                 :  *
    1109                 :  * @param pszText text to append.
    1110                 :  */
    1111                 : 
    1112               0 : void CPLODBCStatement::Append( const char *pszText )
    1113                 : 
    1114                 : {
    1115               0 :     size_t  nTextLen = strlen(pszText);
    1116                 : 
    1117               0 :     if( m_nStatementMax < m_nStatementLen + nTextLen + 1 )
    1118                 :     {
    1119               0 :         m_nStatementMax = (m_nStatementLen + nTextLen) * 2 + 100;
    1120               0 :         if( m_pszStatement == NULL )
    1121                 :         {
    1122               0 :             m_pszStatement = (char *) VSIMalloc(m_nStatementMax);
    1123               0 :             m_pszStatement[0] = '\0';
    1124                 :         }
    1125                 :         else
    1126                 :         {
    1127               0 :             m_pszStatement = (char *) VSIRealloc(m_pszStatement, m_nStatementMax);
    1128                 :         }
    1129                 :     }
    1130                 : 
    1131               0 :     strcpy( m_pszStatement + m_nStatementLen, pszText );
    1132               0 :     m_nStatementLen += nTextLen;
    1133               0 : }
    1134                 : 
    1135                 : /************************************************************************/
    1136                 : /*                     AppendEscaped(const char *)                      */
    1137                 : /************************************************************************/
    1138                 : 
    1139                 : /**
    1140                 :  * Append text to internal command.
    1141                 :  *
    1142                 :  * The passed text is appended to the internal SQL command text after 
    1143                 :  * escaping any special characters so it can be used as a character string
    1144                 :  * in an SQL statement. 
    1145                 :  *
    1146                 :  * @param pszText text to append.
    1147                 :  */
    1148                 : 
    1149               0 : void CPLODBCStatement::AppendEscaped( const char *pszText )
    1150                 : 
    1151                 : {
    1152               0 :     size_t  iIn, iOut ,nTextLen = strlen(pszText);
    1153               0 :     char    *pszEscapedText = (char *) VSIMalloc(nTextLen*2 + 1);
    1154                 : 
    1155               0 :     for( iIn = 0, iOut = 0; iIn < nTextLen; iIn++ )
    1156                 :     {
    1157               0 :         switch( pszText[iIn] )
    1158                 :         {
    1159                 :             case '\'':
    1160                 :             case '\\':
    1161               0 :                 pszEscapedText[iOut++] = '\\';
    1162               0 :                 pszEscapedText[iOut++] = pszText[iIn];
    1163               0 :                 break;
    1164                 : 
    1165                 :             default:
    1166               0 :                 pszEscapedText[iOut++] = pszText[iIn];
    1167                 :                 break;
    1168                 :         }
    1169                 :     }
    1170                 : 
    1171               0 :     pszEscapedText[iOut] = '\0';
    1172                 : 
    1173               0 :     Append( pszEscapedText );
    1174               0 :     CPLFree( pszEscapedText );
    1175               0 : }
    1176                 : 
    1177                 : /************************************************************************/
    1178                 : /*                             Append(int)                              */
    1179                 : /************************************************************************/
    1180                 : 
    1181                 : /**
    1182                 :  * Append to internal command.
    1183                 :  *
    1184                 :  * The passed value is formatted and appended to the internal SQL command text.
    1185                 :  *
    1186                 :  * @param nValue value to append to the command.
    1187                 :  */
    1188                 : 
    1189               0 : void CPLODBCStatement::Append( int nValue )
    1190                 : 
    1191                 : {
    1192                 :     char szFormattedValue[100];
    1193                 : 
    1194               0 :     sprintf( szFormattedValue, "%d", nValue );
    1195               0 :     Append( szFormattedValue );
    1196               0 : }
    1197                 : 
    1198                 : /************************************************************************/
    1199                 : /*                            Append(double)                            */
    1200                 : /************************************************************************/
    1201                 : 
    1202                 : /**
    1203                 :  * Append to internal command.
    1204                 :  *
    1205                 :  * The passed value is formatted and appended to the internal SQL command text.
    1206                 :  *
    1207                 :  * @param dfValue value to append to the command.
    1208                 :  */
    1209                 : 
    1210               0 : void CPLODBCStatement::Append( double dfValue )
    1211                 : 
    1212                 : {
    1213                 :     char szFormattedValue[100];
    1214                 : 
    1215               0 :     sprintf( szFormattedValue, "%24g", dfValue );
    1216               0 :     Append( szFormattedValue );
    1217               0 : }
    1218                 : 
    1219                 : /************************************************************************/
    1220                 : /*                              Appendf()                               */
    1221                 : /************************************************************************/
    1222                 : 
    1223                 : /**
    1224                 :  * Append to internal command.
    1225                 :  *
    1226                 :  * The passed format is used to format other arguments and the result is
    1227                 :  * appended to the internal command text.  Long results may not be formatted
    1228                 :  * properly, and should be appended with the direct Append() methods.
    1229                 :  *
    1230                 :  * @param pszFormat printf() style format string.
    1231                 :  * 
    1232                 :  * @return FALSE if formatting fails dueto result being too large.
    1233                 :  */
    1234                 : 
    1235               0 : int CPLODBCStatement::Appendf( const char *pszFormat, ... )
    1236                 : 
    1237                 : {
    1238                 :     va_list args;
    1239                 :     char    szFormattedText[8000];
    1240                 :     int     bSuccess;
    1241                 : 
    1242               0 :     va_start( args, pszFormat );
    1243                 : #if defined(HAVE_VSNPRINTF)
    1244                 :     bSuccess = vsnprintf( szFormattedText, sizeof(szFormattedText)-1, 
    1245               0 :                           pszFormat, args ) < (int) sizeof(szFormattedText)-1;
    1246                 : #else
    1247                 :     vsprintf( szFormattedText, pszFormat, args );
    1248                 :     bSuccess = TRUE;
    1249                 : #endif
    1250               0 :     va_end( args );
    1251                 : 
    1252               0 :     if( bSuccess )
    1253               0 :         Append( szFormattedText );
    1254                 : 
    1255               0 :     return bSuccess;
    1256                 : }
    1257                 :                                 
    1258                 : /************************************************************************/
    1259                 : /*                               Clear()                                */
    1260                 : /************************************************************************/
    1261                 : 
    1262                 : /**
    1263                 :  * Clear internal command text and result set definitions.
    1264                 :  */
    1265                 : 
    1266               0 : void CPLODBCStatement::Clear()
    1267                 : 
    1268                 : {
    1269                 :     /* Closing the cursor if opened */
    1270               0 :     if( m_hStmt != NULL )
    1271               0 :         SQLFreeStmt( m_hStmt, SQL_CLOSE );
    1272                 :     
    1273               0 :     ClearColumnData();
    1274                 : 
    1275               0 :     if( m_pszStatement != NULL )
    1276                 :     {
    1277               0 :         CPLFree( m_pszStatement );
    1278               0 :         m_pszStatement = NULL;
    1279                 :     }
    1280                 : 
    1281               0 :     m_nStatementLen = 0;
    1282               0 :     m_nStatementMax = 0;
    1283                 : 
    1284               0 :     m_nColCount = 0;
    1285                 : 
    1286               0 :     if( m_papszColNames )
    1287                 :     {
    1288               0 :         CPLFree( m_panColType );
    1289               0 :         m_panColType = NULL;
    1290                 : 
    1291               0 :         CSLDestroy( m_papszColTypeNames );
    1292               0 :         m_papszColTypeNames = NULL;
    1293                 : 
    1294               0 :         CPLFree( m_panColSize );
    1295               0 :         m_panColSize = NULL;
    1296                 : 
    1297               0 :         CPLFree( m_panColPrecision );
    1298               0 :         m_panColPrecision = NULL;
    1299                 : 
    1300               0 :         CPLFree( m_panColNullable );
    1301               0 :         m_panColNullable = NULL;
    1302                 : 
    1303               0 :         CSLDestroy( m_papszColNames );
    1304               0 :         m_papszColNames = NULL;
    1305                 : 
    1306               0 :         CPLFree( m_papszColValues );
    1307               0 :         m_papszColValues = NULL;
    1308                 : 
    1309               0 :         CPLFree( m_panColValueLengths );
    1310               0 :         m_panColValueLengths = NULL;
    1311                 :     }
    1312                 : 
    1313               0 : }
    1314                 : 
    1315                 : /************************************************************************/
    1316                 : /*                             GetColumns()                             */
    1317                 : /************************************************************************/
    1318                 : 
    1319                 : /**
    1320                 :  * Fetch column definitions for a table.
    1321                 :  *
    1322                 :  * The SQLColumn() method is used to fetch the definitions for the columns
    1323                 :  * of a table (or other queriable object such as a view).  The column
    1324                 :  * definitions are digested and used to populate the CPLODBCStatement
    1325                 :  * column definitions essentially as if a "SELECT * FROM tablename" had
    1326                 :  * been done; however, no resultset will be available.
    1327                 :  *
    1328                 :  * @param pszTable the name of the table to query information on.  This
    1329                 :  * should not be empty.
    1330                 :  *
    1331                 :  * @param pszCatalog the catalog to find the table in, use NULL (the
    1332                 :  * default) if no catalog is available. 
    1333                 :  *
    1334                 :  * @param pszSchema the schema to find the table in, use NULL (the
    1335                 :  * default) if no schema is available. 
    1336                 :  *
    1337                 :  * @return TRUE on success or FALSE on failure. 
    1338                 :  */
    1339                 : 
    1340               0 : int CPLODBCStatement::GetColumns( const char *pszTable, 
    1341                 :                                   const char *pszCatalog,
    1342                 :                                   const char *pszSchema )
    1343                 : 
    1344                 : {
    1345                 : #ifdef notdef
    1346                 :     if( pszCatalog == NULL )
    1347                 :         pszCatalog = "";
    1348                 :     if( pszSchema == NULL )
    1349                 :         pszSchema = "";
    1350                 : #endif
    1351                 : 
    1352                 : #if (ODBCVER >= 0x0300)
    1353                 : 
    1354               0 :     if ( !m_poSession->IsInTransaction() )
    1355                 :     {
    1356                 :         /* commit pending transactions and set to autocommit mode*/
    1357               0 :         m_poSession->ClearTransaction();
    1358                 :     }
    1359                 : 
    1360                 : #endif
    1361                 : /* -------------------------------------------------------------------- */
    1362                 : /*      Fetch columns resultset for this table.                         */
    1363                 : /* -------------------------------------------------------------------- */
    1364               0 :     if( Failed( SQLColumns( m_hStmt, 
    1365                 :                             (SQLCHAR *) pszCatalog, SQL_NTS,
    1366                 :                             (SQLCHAR *) pszSchema, SQL_NTS,
    1367                 :                             (SQLCHAR *) pszTable, SQL_NTS,
    1368                 :                             (SQLCHAR *) NULL /* "" */, SQL_NTS ) ) )
    1369               0 :         return FALSE;
    1370                 : 
    1371                 : /* -------------------------------------------------------------------- */
    1372                 : /*      Allocate per column information.                                */
    1373                 : /* -------------------------------------------------------------------- */
    1374                 : #ifdef notdef
    1375                 :     // SQLRowCount() is too unreliable (with unixodbc on AIX for instance)
    1376                 :     // so we now avoid it.
    1377                 :     SQLINTEGER nResultCount=0;
    1378                 : 
    1379                 :     if( Failed(SQLRowCount( m_hStmt, &nResultCount ) ) )
    1380                 :         nResultCount = 0;
    1381                 : 
    1382                 :     if( nResultCount < 1 )
    1383                 :         m_nColCount = 500; // Hopefully lots.
    1384                 :     else
    1385                 :         m_nColCount = nResultCount;
    1386                 : #endif
    1387                 : 
    1388               0 :     m_nColCount = 500;
    1389                 :     
    1390               0 :     m_papszColNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
    1391               0 :     m_papszColValues = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
    1392                 : 
    1393               0 :     m_panColType = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
    1394               0 :     m_papszColTypeNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
    1395               0 :     m_panColSize = (_SQLULEN *) CPLCalloc(sizeof(_SQLULEN),m_nColCount);
    1396               0 :     m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
    1397               0 :     m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
    1398                 : 
    1399                 : /* -------------------------------------------------------------------- */
    1400                 : /*      Establish columns to use for key information.                   */
    1401                 : /* -------------------------------------------------------------------- */
    1402                 :     SQLUSMALLINT iCol;
    1403                 : 
    1404               0 :     for( iCol = 0; iCol < m_nColCount; iCol++ )
    1405                 :     {
    1406                 :         char szWrkData[8193];
    1407                 :         _SQLLEN cbDataLen;
    1408                 : 
    1409               0 :         if( Failed( SQLFetch( m_hStmt ) ) )
    1410                 :         {
    1411               0 :             m_nColCount = iCol;
    1412               0 :             break;
    1413                 :         }
    1414                 : 
    1415               0 :         szWrkData[0] = '\0';
    1416                 : 
    1417                 :         SQLGetData( m_hStmt, SQLColumns_COLUMN_NAME, SQL_C_CHAR,
    1418               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1419               0 :         m_papszColNames[iCol] = CPLStrdup(szWrkData);
    1420                 : 
    1421                 :         SQLGetData( m_hStmt, SQLColumns_DATA_TYPE, SQL_C_CHAR,
    1422               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1423               0 :         m_panColType[iCol] = (short) atoi(szWrkData);
    1424                 : 
    1425                 :         SQLGetData( m_hStmt, SQLColumns_TYPE_NAME, SQL_C_CHAR,
    1426               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1427               0 :         m_papszColTypeNames[iCol] = CPLStrdup(szWrkData);
    1428                 : 
    1429                 :         SQLGetData( m_hStmt, SQLColumns_COLUMN_SIZE, SQL_C_CHAR,
    1430               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1431               0 :         m_panColSize[iCol] = atoi(szWrkData);
    1432                 : 
    1433                 :         SQLGetData( m_hStmt, SQLColumns_DECIMAL_DIGITS, SQL_C_CHAR,
    1434               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1435               0 :         m_panColPrecision[iCol] = (short) atoi(szWrkData);
    1436                 : 
    1437                 :         SQLGetData( m_hStmt, SQLColumns_NULLABLE, SQL_C_CHAR,
    1438               0 :                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
    1439               0 :         m_panColNullable[iCol] = atoi(szWrkData) == SQL_NULLABLE;
    1440                 :     }
    1441                 : 
    1442               0 :     return TRUE;
    1443                 : }
    1444                 : 
    1445                 : /************************************************************************/
    1446                 : /*                           GetPrimaryKeys()                           */
    1447                 : /************************************************************************/
    1448                 : 
    1449                 : /**
    1450                 :  * Fetch primary keys for a table.
    1451                 :  *
    1452                 :  * The SQLPrimaryKeys() function is used to fetch a list of fields
    1453                 :  * forming the primary key.  The result is returned as a result set matching
    1454                 :  * the SQLPrimaryKeys() function result set.  The 4th column in the result
    1455                 :  * set is the column name of the key, and if the result set contains only
    1456                 :  * one record then that single field will be the complete primary key.
    1457                 :  *
    1458                 :  * @param pszTable the name of the table to query information on.  This
    1459                 :  * should not be empty.
    1460                 :  *
    1461                 :  * @param pszCatalog the catalog to find the table in, use NULL (the
    1462                 :  * default) if no catalog is available. 
    1463                 :  *
    1464                 :  * @param pszSchema the schema to find the table in, use NULL (the
    1465                 :  * default) if no schema is available. 
    1466                 :  *
    1467                 :  * @return TRUE on success or FALSE on failure. 
    1468                 :  */
    1469                 : 
    1470               0 : int CPLODBCStatement::GetPrimaryKeys( const char *pszTable, 
    1471                 :                                       const char *pszCatalog,
    1472                 :                                       const char *pszSchema )
    1473                 : 
    1474                 : {
    1475               0 :     if( pszCatalog == NULL )
    1476               0 :         pszCatalog = "";
    1477               0 :     if( pszSchema == NULL )
    1478               0 :         pszSchema = "";
    1479                 : 
    1480                 : #if (ODBCVER >= 0x0300)
    1481                 : 
    1482               0 :     if ( !m_poSession->IsInTransaction() )
    1483                 :     {
    1484                 :         /* commit pending transactions and set to autocommit mode*/
    1485               0 :         m_poSession->ClearTransaction();
    1486                 :     }
    1487                 : 
    1488                 : #endif
    1489                 : 
    1490                 : /* -------------------------------------------------------------------- */
    1491                 : /*      Fetch columns resultset for this table.                         */
    1492                 : /* -------------------------------------------------------------------- */
    1493               0 :     if( Failed( SQLPrimaryKeys( m_hStmt, 
    1494                 :                                 (SQLCHAR *) pszCatalog, SQL_NTS,
    1495                 :                                 (SQLCHAR *) pszSchema, SQL_NTS,
    1496                 :                                 (SQLCHAR *) pszTable, SQL_NTS ) ) )
    1497               0 :         return FALSE;
    1498                 :     else
    1499               0 :         return CollectResultsInfo();
    1500                 : }
    1501                 : 
    1502                 : /************************************************************************/
    1503                 : /*                             GetTables()                              */
    1504                 : /************************************************************************/
    1505                 : 
    1506                 : /**
    1507                 :  * Fetch tables in database.
    1508                 :  *
    1509                 :  * The SQLTables() function is used to fetch a list tables in the
    1510                 :  * database.    The result is returned as a result set matching
    1511                 :  * the SQLTables() function result set.  The 3rd column in the result
    1512                 :  * set is the table name.  Only tables of type "TABLE" are returned. 
    1513                 :  *
    1514                 :  * @param pszCatalog the catalog to find the table in, use NULL (the
    1515                 :  * default) if no catalog is available. 
    1516                 :  *
    1517                 :  * @param pszSchema the schema to find the table in, use NULL (the
    1518                 :  * default) if no schema is available. 
    1519                 :  *
    1520                 :  * @return TRUE on success or FALSE on failure. 
    1521                 :  */
    1522                 : 
    1523               0 : int CPLODBCStatement::GetTables( const char *pszCatalog,
    1524                 :                                  const char *pszSchema )
    1525                 : 
    1526                 : {
    1527                 :     CPLDebug( "ODBC", "CatalogNameL: %s\nSchema name: %s\n",
    1528               0 :                 pszCatalog, pszSchema );
    1529                 : 
    1530                 : #if (ODBCVER >= 0x0300)
    1531                 : 
    1532               0 :     if ( !m_poSession->IsInTransaction() )
    1533                 :     {
    1534                 :         /* commit pending transactions and set to autocommit mode*/
    1535               0 :         m_poSession->ClearTransaction();
    1536                 :     }
    1537                 : 
    1538                 : #endif
    1539                 : 
    1540                 : /* -------------------------------------------------------------------- */
    1541                 : /*      Fetch columns resultset for this table.                         */
    1542                 : /* -------------------------------------------------------------------- */
    1543               0 :     if( Failed( SQLTables( m_hStmt, 
    1544                 :                            (SQLCHAR *) pszCatalog, SQL_NTS,
    1545                 :                            (SQLCHAR *) pszSchema, SQL_NTS,
    1546                 :                            (SQLCHAR *) NULL, SQL_NTS,
    1547                 :                            (SQLCHAR *) "'TABLE','VIEW'", SQL_NTS ) ) )
    1548               0 :         return FALSE;
    1549                 :     else
    1550               0 :         return CollectResultsInfo();
    1551                 : }
    1552                 : 
    1553                 : /************************************************************************/
    1554                 : /*                             DumpResult()                             */
    1555                 : /************************************************************************/
    1556                 : 
    1557                 : /**
    1558                 :  * Dump resultset to file.
    1559                 :  *
    1560                 :  * The contents of the current resultset are dumped in a simply formatted
    1561                 :  * form to the provided file.  If requested, the schema definition will
    1562                 :  * be written first. 
    1563                 :  *
    1564                 :  * @param fp the file to write to.  stdout or stderr are acceptable. 
    1565                 :  *
    1566                 :  * @param bShowSchema TRUE to force writing schema information for the rowset
    1567                 :  * before the rowset data itself.  Default is FALSE.
    1568                 :  */
    1569                 : 
    1570               0 : void CPLODBCStatement::DumpResult( FILE *fp, int bShowSchema )
    1571                 : 
    1572                 : {
    1573                 :     int iCol;
    1574                 : 
    1575                 : /* -------------------------------------------------------------------- */
    1576                 : /*      Display schema                                                  */
    1577                 : /* -------------------------------------------------------------------- */
    1578               0 :     if( bShowSchema )
    1579                 :     {
    1580               0 :         fprintf( fp, "Column Definitions:\n" );
    1581               0 :         for( iCol = 0; iCol < GetColCount(); iCol++ )
    1582                 :         {
    1583               0 :             fprintf( fp, " %2d: %-24s ", iCol, GetColName(iCol) );
    1584               0 :             if( GetColPrecision(iCol) > 0 
    1585                 :                 && GetColPrecision(iCol) != GetColSize(iCol) )
    1586                 :                 fprintf( fp, " Size:%3d.%d", 
    1587               0 :                          GetColSize(iCol), GetColPrecision(iCol) );
    1588                 :             else
    1589               0 :                 fprintf( fp, " Size:%5d", GetColSize(iCol) );
    1590                 : 
    1591               0 :             CPLString osType = GetTypeName( GetColType(iCol) );
    1592               0 :             fprintf( fp, " Type:%s", osType.c_str() );
    1593               0 :             if( GetColNullable(iCol) )
    1594               0 :                 fprintf( fp, " NULLABLE" );
    1595               0 :             fprintf( fp, "\n" );
    1596                 :         }
    1597               0 :         fprintf( fp, "\n" );
    1598                 :     }
    1599                 : 
    1600                 : /* -------------------------------------------------------------------- */
    1601                 : /*      Display results                                                 */
    1602                 : /* -------------------------------------------------------------------- */
    1603               0 :     int iRecord = 0;
    1604               0 :     while( Fetch() )
    1605                 :     {
    1606               0 :         fprintf( fp, "Record %d\n", iRecord++ );
    1607                 :         
    1608               0 :         for( iCol = 0; iCol < GetColCount(); iCol++ )
    1609                 :         {
    1610               0 :             fprintf( fp, "  %s: %s\n", GetColName(iCol), GetColData(iCol) );
    1611                 :         }
    1612                 :     }
    1613               0 : }
    1614                 : 
    1615                 : /************************************************************************/
    1616                 : /*                            GetTypeName()                             */
    1617                 : /************************************************************************/
    1618                 : 
    1619                 : /**
    1620                 :  * Get name for SQL column type.
    1621                 :  *
    1622                 :  * Returns a string name for the indicated type code (as returned
    1623                 :  * from CPLODBCStatement::GetColType()).
    1624                 :  *
    1625                 :  * @param nTypeCode the SQL_ code, such as SQL_CHAR.
    1626                 :  *
    1627                 :  * @return internal string, "UNKNOWN" if code not recognised. 
    1628                 :  */
    1629                 : 
    1630               0 : CPLString CPLODBCStatement::GetTypeName( int nTypeCode )
    1631                 : 
    1632                 : {
    1633               0 :     switch( nTypeCode )
    1634                 :     {
    1635                 :       case SQL_CHAR:
    1636               0 :         return "CHAR";
    1637                 :         
    1638                 :       case SQL_NUMERIC:
    1639               0 :         return "NUMERIC";
    1640                 :         
    1641                 :       case SQL_DECIMAL:
    1642               0 :         return "DECIMAL";
    1643                 :         
    1644                 :       case SQL_INTEGER:
    1645               0 :         return "INTEGER";
    1646                 :         
    1647                 :       case SQL_SMALLINT:
    1648               0 :         return "SMALLINT";
    1649                 : 
    1650                 :         
    1651                 :       case SQL_FLOAT:
    1652               0 :         return "FLOAT";
    1653                 :         
    1654                 :       case SQL_REAL:
    1655               0 :         return "REAL";
    1656                 : 
    1657                 :       case SQL_DOUBLE:
    1658               0 :         return "DOUBLE";
    1659                 :         
    1660                 :       case SQL_DATETIME:
    1661               0 :         return "DATETIME";
    1662                 : 
    1663                 :       case SQL_VARCHAR:
    1664               0 :         return "VARCHAR";
    1665                 : 
    1666                 :       case SQL_TYPE_DATE:
    1667               0 :         return "DATE";
    1668                 : 
    1669                 :       case SQL_TYPE_TIME:
    1670               0 :         return "TIME";
    1671                 :         
    1672                 :       case SQL_TYPE_TIMESTAMP:
    1673               0 :         return "TIMESTAMP";
    1674                 : 
    1675                 :       default:
    1676               0 :         CPLString osResult;
    1677               0 :         osResult.Printf( "UNKNOWN:%d", nTypeCode );
    1678               0 :         return osResult;
    1679                 :     }
    1680                 : }
    1681                 : 
    1682                 : /************************************************************************/
    1683                 : /*                            GetTypeMapping()                          */
    1684                 : /************************************************************************/
    1685                 : 
    1686                 : /**
    1687                 :  * Get appropriate C data type for SQL column type.
    1688                 :  *
    1689                 :  * Returns a C data type code, corresponding to the indicated SQL data
    1690                 :  * type code (as returned from CPLODBCStatement::GetColType()).
    1691                 :  *
    1692                 :  * @param nTypeCode the SQL_ code, such as SQL_CHAR.
    1693                 :  *
    1694                 :  * @return data type code. The valid code is always returned. If SQL
    1695                 :  * code is not recognised, SQL_C_BINARY will be returned.
    1696                 :  */
    1697                 : 
    1698               0 : SQLSMALLINT CPLODBCStatement::GetTypeMapping( SQLSMALLINT nTypeCode )
    1699                 : 
    1700                 : {
    1701               0 :     switch( nTypeCode )
    1702                 :     {
    1703                 :         case SQL_CHAR:
    1704                 :         case SQL_VARCHAR:
    1705                 :         case SQL_LONGVARCHAR:
    1706               0 :             return SQL_C_CHAR;
    1707                 : 
    1708                 :         case SQL_WCHAR:
    1709                 :         case SQL_WVARCHAR:
    1710                 :         case SQL_WLONGVARCHAR:
    1711               0 :             return SQL_C_WCHAR;
    1712                 : 
    1713                 :         case SQL_DECIMAL:
    1714                 :         case SQL_NUMERIC:
    1715               0 :             return SQL_C_NUMERIC;
    1716                 : 
    1717                 :         case SQL_SMALLINT:
    1718               0 :             return SQL_C_SSHORT;
    1719                 : 
    1720                 :         case SQL_INTEGER:
    1721               0 :             return SQL_C_SLONG;
    1722                 : 
    1723                 :         case SQL_REAL:
    1724               0 :             return SQL_C_FLOAT;
    1725                 : 
    1726                 :         case SQL_FLOAT:
    1727                 :         case SQL_DOUBLE:
    1728               0 :             return SQL_C_DOUBLE;
    1729                 : 
    1730                 :         case SQL_BIT:
    1731                 :         case SQL_TINYINT:
    1732                 :         case SQL_BIGINT:
    1733                 : /*        case SQL_TYPE_UTCDATETIME:
    1734                 :         case SQL_TYPE_UTCTIME:*/
    1735                 :         case SQL_INTERVAL_MONTH:
    1736                 :         case SQL_INTERVAL_YEAR:
    1737                 :         case SQL_INTERVAL_YEAR_TO_MONTH:
    1738                 :         case SQL_INTERVAL_DAY:
    1739                 :         case SQL_INTERVAL_HOUR:
    1740                 :         case SQL_INTERVAL_MINUTE:
    1741                 :         case SQL_INTERVAL_SECOND:
    1742                 :         case SQL_INTERVAL_DAY_TO_HOUR:
    1743                 :         case SQL_INTERVAL_DAY_TO_MINUTE:
    1744                 :         case SQL_INTERVAL_DAY_TO_SECOND:
    1745                 :         case SQL_INTERVAL_HOUR_TO_MINUTE:
    1746                 :         case SQL_INTERVAL_HOUR_TO_SECOND:
    1747                 :         case SQL_INTERVAL_MINUTE_TO_SECOND:
    1748                 :         case SQL_GUID:
    1749               0 :             return SQL_C_CHAR;
    1750                 : 
    1751                 :         case SQL_DATE:
    1752                 :         case SQL_TYPE_DATE:
    1753               0 :             return SQL_C_DATE;
    1754                 : 
    1755                 :         case SQL_TIME:
    1756                 :         case SQL_TYPE_TIME:
    1757               0 :             return SQL_C_TIME;
    1758                 : 
    1759                 :         case SQL_TIMESTAMP:
    1760                 :         case SQL_TYPE_TIMESTAMP:
    1761               0 :             return SQL_C_TIMESTAMP;
    1762                 : 
    1763                 :         case SQL_BINARY:
    1764                 :         case SQL_VARBINARY:
    1765                 :         case SQL_LONGVARBINARY:
    1766               0 :             return SQL_C_BINARY;
    1767                 : 
    1768                 :         default:
    1769               0 :             return SQL_C_CHAR;
    1770                 :     }
    1771                 : }
    1772                 : 
    1773                 : #endif /* #ifndef WIN32CE */

Generated by: LCOV version 1.7