LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLGetDiagField.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 150 26.0 %
Date: 2024-10-03 20:03:20 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * This code was created by Peter Harvey (mostly during Christmas 98/99).
      15             :  * This code is LGPL. Please ensure that this message remains in future
      16             :  * distributions and uses of this code (that's about all I get out of it).
      17             :  * - Peter Harvey pharvey@codebydesign.com
      18             :  *
      19             :  * This file has been modified for the MonetDB project.  See the file
      20             :  * Copyright in this directory for more information.
      21             :  */
      22             : 
      23             : /**********************************************************************
      24             :  * SQLGetDiagField()
      25             :  * ODBC 3.0 API function
      26             :  * CLI Compliance: ISO 92
      27             :  **********************************************************************/
      28             : 
      29             : #include "ODBCGlobal.h"
      30             : #include "ODBCEnv.h"
      31             : #include "ODBCDbc.h"
      32             : #include "ODBCStmt.h"
      33             : #include "ODBCError.h"
      34             : #include "ODBCUtil.h"
      35             : 
      36             : #define copyDiagString(str, buf, len, lenp)                             \
      37             :                 do {                                                    \
      38             :                         size_t _l;                                      \
      39             :                         if (len < 0)                                 \
      40             :                                 return SQL_ERROR;                       \
      41             :                         _l = strcpy_len((char *) buf, str, len);        \
      42             :                         if (lenp)                                       \
      43             :                                 *lenp = (SQLSMALLINT) _l;               \
      44             :                         if (buf == NULL || _l >= (size_t) len)               \
      45             :                                 return SQL_SUCCESS_WITH_INFO;           \
      46             :                 } while (0)
      47             : 
      48             : static SQLRETURN
      49          12 : MNDBGetDiagField(SQLSMALLINT HandleType,
      50             :                  SQLHANDLE Handle,
      51             :                  SQLSMALLINT RecNumber,
      52             :                  SQLSMALLINT DiagIdentifier,
      53             :                  SQLPOINTER DiagInfoPtr,
      54             :                  SQLSMALLINT BufferLength,
      55             :                  SQLSMALLINT *StringLengthPtr)
      56             : {
      57          12 :         ODBCError *err;
      58          12 :         ODBCDbc *dbc = NULL;
      59             : 
      60             :         /* input & output parameters validity checks */
      61             : 
      62          12 :         switch (HandleType) {
      63           0 :         case SQL_HANDLE_ENV:
      64             :                 /* Check if this struct is still valid/alive */
      65           0 :                 if (!isValidEnv((ODBCEnv *) Handle))
      66             :                         return SQL_INVALID_HANDLE;
      67           0 :                 err = getEnvError((ODBCEnv *) Handle);
      68           0 :                 break;
      69          12 :         case SQL_HANDLE_DBC:
      70             :                 /* Check if this struct is still valid/alive */
      71          12 :                 dbc = (ODBCDbc *) Handle;
      72          12 :                 if (!isValidDbc(dbc))
      73             :                         return SQL_INVALID_HANDLE;
      74          12 :                 err = getDbcError(dbc);
      75          12 :                 break;
      76           0 :         case SQL_HANDLE_STMT:
      77             :                 /* Check if this struct is still valid/alive */
      78           0 :                 if (!isValidStmt((ODBCStmt *) Handle))
      79             :                         return SQL_INVALID_HANDLE;
      80           0 :                 err = getStmtError((ODBCStmt *) Handle);
      81           0 :                 dbc = ((ODBCStmt *) Handle)->Dbc;
      82           0 :                 break;
      83           0 :         case SQL_HANDLE_DESC:
      84             :                 /* Check if this struct is still valid/alive */
      85           0 :                 if (!isValidDesc((ODBCDesc *) Handle))
      86             :                         return SQL_INVALID_HANDLE;
      87           0 :                 err = getDescError((ODBCDesc *) Handle);
      88           0 :                 dbc = ((ODBCDesc *) Handle)->Dbc;
      89           0 :                 break;
      90             :         default:
      91             :                 return SQL_INVALID_HANDLE;
      92             :         }
      93             : 
      94             :         /* header fields */
      95          12 :         switch (DiagIdentifier) {
      96           0 :         case SQL_DIAG_CURSOR_ROW_COUNT:         /* SQLLEN */
      97           0 :                 if (HandleType != SQL_HANDLE_STMT)
      98             :                         return SQL_ERROR;
      99           0 :                 *(SQLLEN *) DiagInfoPtr = (SQLLEN) ((ODBCStmt *) Handle)->rowSetSize;
     100           0 :                 return SQL_SUCCESS;
     101           0 :         case SQL_DIAG_DYNAMIC_FUNCTION:         /* SQLCHAR* */
     102           0 :                 if (HandleType != SQL_HANDLE_STMT)
     103             :                         return SQL_ERROR;
     104           0 :                 copyDiagString("", DiagInfoPtr, BufferLength, StringLengthPtr);
     105             :                 return SQL_SUCCESS;
     106           0 :         case SQL_DIAG_DYNAMIC_FUNCTION_CODE:    /* SQLINTEGER */
     107           0 :                 if (HandleType != SQL_HANDLE_STMT)
     108             :                         return SQL_ERROR;
     109           0 :                 *(SQLINTEGER *) DiagInfoPtr = SQL_DIAG_UNKNOWN_STATEMENT;
     110           0 :                 return SQL_SUCCESS;
     111           0 :         case SQL_DIAG_NUMBER:                   /* SQLINTEGER */
     112           0 :                 *(SQLINTEGER *) DiagInfoPtr = getErrorRecCount(err);
     113           0 :                 return SQL_SUCCESS;
     114           0 :         case SQL_DIAG_RETURNCODE:               /* SQLRETURN */
     115           0 :                 *(SQLRETURN *) DiagInfoPtr = SQL_SUCCESS;
     116           0 :                 return SQL_SUCCESS;
     117           0 :         case SQL_DIAG_ROW_COUNT:                /* SQLLEN */
     118           0 :                 if (HandleType != SQL_HANDLE_STMT || ((ODBCStmt *) Handle)->State < EXECUTED0)
     119             :                         return SQL_ERROR;
     120           0 :                 *(SQLLEN *) DiagInfoPtr = (SQLLEN) ((ODBCStmt *) Handle)->rowcount;
     121           0 :                 return SQL_SUCCESS;
     122             :         }
     123             : 
     124             :         /* record fields */
     125          12 :         if (RecNumber <= 0)
     126             :                 return SQL_ERROR;
     127             : 
     128          12 :         err = getErrorRec(err, RecNumber);
     129          12 :         if (err == NULL)
     130             :                 return SQL_NO_DATA;
     131             : 
     132          12 :         switch (DiagIdentifier) {
     133           3 :         case SQL_DIAG_CLASS_ORIGIN:{            /* SQLCHAR* */
     134           3 :                 char *msg = strncmp(getSqlState(err), "IM", 2) == 0 ? "ODBC 3.0" : "ISO 9075";
     135             : 
     136           3 :                 copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
     137             :                 return SQL_SUCCESS;
     138             :         }
     139           0 :         case SQL_DIAG_COLUMN_NUMBER:            /* SQLINTEGER */
     140           0 :                 if (HandleType != SQL_HANDLE_STMT)
     141             :                         return SQL_ERROR;
     142           0 :                 *(SQLINTEGER *) DiagInfoPtr = SQL_COLUMN_NUMBER_UNKNOWN;
     143           0 :                 return SQL_SUCCESS;
     144           3 :         case SQL_DIAG_CONNECTION_NAME:{         /* SQLCHAR* */
     145           3 :                 char *msg = "MonetDB ODBC/Mapi";
     146             : 
     147           3 :                 copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
     148             :                 return SQL_SUCCESS;
     149             :         }
     150           0 :         case SQL_DIAG_MESSAGE_TEXT:{            /* SQLCHAR* */
     151           0 :                 char *msg = getMessage(err);
     152             : 
     153             :                 /* first write the error message prefix text:
     154             :                  * [MonetDB][ODBC driver VERSION][DSN]
     155             :                  * this is required by the ODBC spec:
     156             :                  * https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/diagnostic-messages
     157             :                  * and used to determine where the error originated
     158             :                  */
     159           0 :                 SQLSMALLINT msgLen;
     160           0 :                 if (dbc && dbc->dsn)
     161           0 :                         msgLen = (SQLSMALLINT) strconcat_len((char *) DiagInfoPtr, BufferLength, ODBCErrorMsgPrefix, "[", dbc->dsn, "]", msg, NULL);
     162             :                 else
     163           0 :                         msgLen = (SQLSMALLINT) strconcat_len((char *) DiagInfoPtr, BufferLength, ODBCErrorMsgPrefix, msg, NULL);
     164           0 :                 if (StringLengthPtr)
     165           0 :                         *StringLengthPtr = msgLen;
     166           0 :                 if (DiagInfoPtr == NULL || msgLen >= BufferLength)
     167             :                         return SQL_SUCCESS_WITH_INFO;
     168             :                 return SQL_SUCCESS;
     169             :         }
     170           0 :         case SQL_DIAG_NATIVE:                   /* SQLINTEGER */
     171           0 :                 *(SQLINTEGER *) DiagInfoPtr = getNativeErrorCode(err);
     172           0 :                 return SQL_SUCCESS;
     173           0 :         case SQL_DIAG_ROW_NUMBER:               /* SQLLEN */
     174           0 :                 if (HandleType != SQL_HANDLE_STMT)
     175             :                         return SQL_ERROR;
     176           0 :                 *(SQLLEN *) DiagInfoPtr = SQL_ROW_NUMBER_UNKNOWN;
     177           0 :                 return SQL_SUCCESS;
     178           3 :         case SQL_DIAG_SERVER_NAME:{             /* SQLCHAR* */
     179           3 :                 char *msg = dbc && dbc->Connected && dbc->dsn ? dbc->dsn : "";
     180             : 
     181           3 :                 copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
     182             :                 return SQL_SUCCESS;
     183             :         }
     184           0 :         case SQL_DIAG_SQLSTATE:{                /* SQLCHAR* */
     185           0 :                 char *msg = getSqlState(err);
     186             : 
     187           0 :                 copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
     188             :                 return SQL_SUCCESS;
     189             :         }
     190           3 :         case SQL_DIAG_SUBCLASS_ORIGIN:{         /* SQLCHAR* */
     191           3 :                 char *state = getSqlState(err);
     192           3 :                 char *msg;
     193             : 
     194           3 :                 if (('0' <= state[0] && state[0] <= '4') ||
     195             :                     ('A' <= state[0] && state[0] <= 'H'))
     196             :                         msg = "ISO 9075"; /* defined by standard */
     197             :                 else
     198           0 :                         msg = "ODBC 3.0"; /* effectively just "IM" */
     199             : 
     200           3 :                 copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
     201             :                 return SQL_SUCCESS;
     202             :         }
     203             :         }
     204             : 
     205             :         /* Currently no Diagnostic Fields are supported.
     206             :            Hence we always return NO_DATA */
     207             :         return SQL_NO_DATA;
     208             : }
     209             : 
     210             : #ifdef ODBCDEBUG
     211             : static char *
     212          12 : translateDiagIdentifier(SQLSMALLINT DiagIdentifier)
     213             : {
     214          12 :         static char unknown[32];
     215             : 
     216          12 :         switch (DiagIdentifier) {
     217             :         case SQL_DIAG_CLASS_ORIGIN:
     218             :                 return "SQL_DIAG_CLASS_ORIGIN";
     219           0 :         case SQL_DIAG_COLUMN_NUMBER:
     220           0 :                 return "SQL_DIAG_COLUMN_NUMBER";
     221           3 :         case SQL_DIAG_CONNECTION_NAME:
     222           3 :                 return "SQL_DIAG_CONNECTION_NAME";
     223           0 :         case SQL_DIAG_CURSOR_ROW_COUNT:
     224           0 :                 return "SQL_DIAG_CURSOR_ROW_COUNT";
     225           0 :         case SQL_DIAG_DYNAMIC_FUNCTION:
     226           0 :                 return "SQL_DIAG_DYNAMIC_FUNCTION";
     227           0 :         case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
     228           0 :                 return "SQL_DIAG_DYNAMIC_FUNCTION_CODE";
     229           0 :         case SQL_DIAG_MESSAGE_TEXT:
     230           0 :                 return "SQL_DIAG_MESSAGE_TEXT";
     231           0 :         case SQL_DIAG_NATIVE:
     232           0 :                 return "SQL_DIAG_NATIVE";
     233           0 :         case SQL_DIAG_NUMBER:
     234           0 :                 return "SQL_DIAG_NUMBER";
     235           0 :         case SQL_DIAG_RETURNCODE:
     236           0 :                 return "SQL_DIAG_RETURNCODE";
     237           0 :         case SQL_DIAG_ROW_COUNT:
     238           0 :                 return "SQL_DIAG_ROW_COUNT";
     239           0 :         case SQL_DIAG_ROW_NUMBER:
     240           0 :                 return "SQL_DIAG_ROW_NUMBER";
     241           3 :         case SQL_DIAG_SERVER_NAME:
     242           3 :                 return "SQL_DIAG_SERVER_NAME";
     243           0 :         case SQL_DIAG_SQLSTATE:
     244           0 :                 return "SQL_DIAG_SQLSTATE";
     245           3 :         case SQL_DIAG_SUBCLASS_ORIGIN:
     246           3 :                 return "SQL_DIAG_SUBCLASS_ORIGIN";
     247           0 :         default:
     248           0 :                 snprintf(unknown, sizeof(unknown), "unknown (%d)",
     249             :                          (int) DiagIdentifier);
     250           0 :                 return unknown;
     251             :         }
     252             : }
     253             : #endif
     254             : 
     255             : SQLRETURN SQL_API
     256             : SQLGetDiagField(SQLSMALLINT HandleType,
     257             :                 SQLHANDLE Handle,
     258             :                 SQLSMALLINT RecNumber,
     259             :                 SQLSMALLINT DiagIdentifier,
     260             :                 SQLPOINTER DiagInfoPtr,
     261             :                 SQLSMALLINT BufferLength,
     262             :                 SQLSMALLINT *StringLengthPtr)
     263             : {
     264             : #ifdef ODBCDEBUG
     265          24 :         ODBCLOG("SQLGetDiagField %s %p %d %s %p %d %p\n",
     266             :                 HandleType == SQL_HANDLE_ENV ? "Env" : HandleType == SQL_HANDLE_DBC ? "Dbc" : HandleType == SQL_HANDLE_STMT ? "Stmt" : "Desc",
     267             :                 Handle, (int) RecNumber,
     268             :                 translateDiagIdentifier(DiagIdentifier),
     269             :                 DiagInfoPtr,
     270             :                 (int) BufferLength, StringLengthPtr);
     271             : #endif
     272             : 
     273          12 :         return MNDBGetDiagField(HandleType,
     274             :                                 Handle,
     275             :                                 RecNumber,
     276             :                                 DiagIdentifier,
     277             :                                 DiagInfoPtr,
     278             :                                 BufferLength,
     279             :                                 StringLengthPtr);
     280             : }
     281             : 
     282             : SQLRETURN SQL_API
     283             : SQLGetDiagFieldA(SQLSMALLINT HandleType,
     284             :                  SQLHANDLE Handle,
     285             :                  SQLSMALLINT RecNumber,
     286             :                  SQLSMALLINT DiagIdentifier,
     287             :                  SQLPOINTER DiagInfoPtr,
     288             :                  SQLSMALLINT BufferLength,
     289             :                  SQLSMALLINT *StringLengthPtr)
     290             : {
     291           0 :         return SQLGetDiagField(HandleType,
     292             :                                Handle,
     293             :                                RecNumber,
     294             :                                DiagIdentifier,
     295             :                                DiagInfoPtr,
     296             :                                BufferLength,
     297             :                                StringLengthPtr);
     298             : }
     299             : 
     300             : SQLRETURN SQL_API
     301             : SQLGetDiagFieldW(SQLSMALLINT HandleType,
     302             :                  SQLHANDLE Handle,
     303             :                  SQLSMALLINT RecNumber,
     304             :                  SQLSMALLINT DiagIdentifier,
     305             :                  SQLPOINTER DiagInfoPtr,
     306             :                  SQLSMALLINT BufferLength,
     307             :                  SQLSMALLINT *StringLengthPtr)
     308             : {
     309           0 :         SQLRETURN rc;
     310           0 :         SQLPOINTER ptr = NULL;
     311           0 :         SQLSMALLINT n;
     312             : 
     313             : #ifdef ODBCDEBUG
     314           0 :         ODBCLOG("SQLGetDiagFieldW %s %p %d %s %p %d %p\n",
     315             :                 HandleType == SQL_HANDLE_ENV ? "Env" : HandleType == SQL_HANDLE_DBC ? "Dbc" : HandleType == SQL_HANDLE_STMT ? "Stmt" : "Desc",
     316             :                 Handle, (int) RecNumber,
     317             :                 translateDiagIdentifier(DiagIdentifier),
     318             :                 DiagInfoPtr,
     319             :                 (int) BufferLength, StringLengthPtr);
     320             : #endif
     321             : 
     322           0 :         switch (DiagIdentifier) {
     323             :                 /* all string attributes */
     324           0 :         case SQL_DIAG_DYNAMIC_FUNCTION:
     325             :         case SQL_DIAG_CLASS_ORIGIN:
     326             :         case SQL_DIAG_CONNECTION_NAME:
     327             :         case SQL_DIAG_MESSAGE_TEXT:
     328             :         case SQL_DIAG_SERVER_NAME:
     329             :         case SQL_DIAG_SQLSTATE:
     330             :         case SQL_DIAG_SUBCLASS_ORIGIN:
     331           0 :                 rc = MNDBGetDiagField(HandleType, Handle, RecNumber,
     332             :                                       DiagIdentifier, NULL, 0, &n);
     333           0 :                 if (!SQL_SUCCEEDED(rc))
     334             :                         return rc;
     335           0 :                 n++;            /* account for NUL byte */
     336           0 :                 ptr = (SQLPOINTER) malloc(n);
     337           0 :                 break;
     338           0 :         default:
     339           0 :                 n = BufferLength;
     340           0 :                 ptr = DiagInfoPtr;
     341           0 :                 break;
     342             :         }
     343             : 
     344           0 :         rc = MNDBGetDiagField(HandleType, Handle, RecNumber,
     345             :                               DiagIdentifier, ptr, n, &n);
     346             : #ifdef ODBCDEBUG
     347           0 :         if (ptr != DiagInfoPtr)
     348           0 :                 ODBCLOG("SQLGetDiagFieldW: %s\n", (char *) ptr);
     349             : #endif
     350             : 
     351           0 :         if (ptr != DiagInfoPtr) {
     352           0 :                 if (SQL_SUCCEEDED(rc)) {
     353           0 :                         const char *e = ODBCutf82wchar(ptr, n, DiagInfoPtr,
     354             :                                                        BufferLength / 2, &n,
     355             :                                                        NULL);
     356             : 
     357           0 :                         if (e)
     358           0 :                                 rc = SQL_ERROR;
     359           0 :                         if (StringLengthPtr)
     360           0 :                                 *StringLengthPtr = n * 2;
     361             :                 }
     362           0 :                 free(ptr);
     363             :         }
     364             : 
     365             :         return rc;
     366             : }

Generated by: LCOV version 1.14