LTP GCOV extension - code coverage report
Current view: directory - port - cpl_odbc.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 430
Code covered: 0.0 % Executed lines: 0

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

Generated by: LTP GCOV extension version 1.5