/* * info.c * * $Id$ * * Information functions * * The iODBC driver manager. * * Copyright (C) 1995 by Ke Jin * Copyright (C) 1996-2012 by OpenLink Software * All Rights Reserved. * * This software is released under the terms of either of the following * licenses: * * - GNU Library General Public License (see LICENSE.LGPL) * - The BSD License (see LICENSE.BSD). * * Note that the only valid version of the LGPL license as far as this * project is concerned is the original GNU Library General Public License * Version 2, dated June 1991. * * While not mandated by the BSD license, any patches you make to the * iODBC source code may be contributed back into the iODBC project * at your discretion. Contributions will benefit the Open Source and * Data Access community as a whole. Submissions may be made at: * * http://www.iodbc.org * * * GNU Library Generic Public License Version 2 * ============================================ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; only * Version 2 of the License dated June 1991. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * * The BSD License * =============== * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of OpenLink Software Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #define SECT1 "ODBC 32 bit Data Sources" #define SECT2 "ODBC 32 bit Drivers" #else #define SECT1 "ODBC Data Sources" #define SECT2 "ODBC Drivers" #endif #define MAX_ENTRIES 1024 static int stricmp (const char *s1, const char *s2) { int cmp; while (*s1) { if ((cmp = toupper (*s1) - toupper (*s2)) != 0) return cmp; s1++; s2++; } return (*s2) ? -1 : 0; } static int SectSorter (const void *p1, const void *p2) { const char **s1 = (const char **) p1; const char **s2 = (const char **) p2; return stricmp (*s1, *s2); } SQLRETURN SQL_API SQLDataSources_Internal ( SQLHENV henv, SQLUSMALLINT fDir, SQLPOINTER szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT * pcbDSN, SQLPOINTER szDesc, SQLSMALLINT cbDescMax, SQLSMALLINT * pcbDesc, SQLCHAR waMode) { GENV (genv, henv); char buffer[4096], desc[1024], *ptr; int i, j, usernum = 0; static int cur_entry = -1; static int num_entries = 0; static void **sect = NULL; SQLUSMALLINT fDirOld = fDir; waMode = waMode; /*UNUSED*/ /* check argument */ if (cbDSNMax < 0 || cbDescMax < 0) { PUSHSQLERR (genv->herr, en_S1090); return SQL_ERROR; } if (fDir != SQL_FETCH_FIRST && fDir != SQL_FETCH_NEXT && fDir != SQL_FETCH_FIRST_USER && fDir != SQL_FETCH_FIRST_SYSTEM) { PUSHSQLERR (genv->herr, en_S1103); return SQL_ERROR; } if (cur_entry < 0 || fDir == SQL_FETCH_FIRST || fDir == SQL_FETCH_FIRST_USER || fDir == SQL_FETCH_FIRST_SYSTEM) { cur_entry = 0; num_entries = 0; /* * Free old section list */ if (sect) { for (i = 0; i < MAX_ENTRIES; i++) if (sect[i]) free (sect[i]); free (sect); } if ((sect = (void **) calloc (MAX_ENTRIES, sizeof (void *))) == NULL) { PUSHSQLERR (genv->herr, en_S1011); return SQL_ERROR; } if (fDirOld == SQL_FETCH_FIRST) fDir = SQL_FETCH_FIRST_USER; do { SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN); SQLGetPrivateProfileString (SECT1, NULL, "", buffer, sizeof(buffer) / sizeof(SQLTCHAR), "odbc.ini"); /* For each datasources */ for(ptr = buffer, i = 1 ; *ptr && i ; ptr += STRLEN(ptr) + 1) { /* Add this section to the datasources list */ if (fDirOld == SQL_FETCH_FIRST && fDir == SQL_FETCH_FIRST_SYSTEM) { for(j = 0 ; j= MAX_ENTRIES) { i = 0; break; } /* Skip the rest */ /* Copy the datasource name */ sect[num_entries<<1] = STRDUP (ptr); /* ... and its description */ SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN); SQLGetPrivateProfileString (SECT1, ptr, "", desc, sizeof(desc) / sizeof(SQLTCHAR), "odbc.ini"); sect[(num_entries++<<1) + 1] = STRDUP (desc); } switch(fDir) { case SQL_FETCH_FIRST_USER: fDir = SQL_FETCH_FIRST_SYSTEM; usernum = num_entries; break; case SQL_FETCH_FIRST_SYSTEM: fDir = SQL_FETCH_FIRST; break; }; } while (fDir!=SQL_FETCH_FIRST && fDirOld==SQL_FETCH_FIRST); fDir = fDirOld; /* * Sort all entries so we can present a nice list */ if (num_entries > 1) { qsort (sect, num_entries, sizeof (char **) + sizeof (char **), SectSorter); } } /* * Try to get to the next item */ if (cur_entry >= num_entries) { cur_entry = 0; /* Next time, start all over again */ return SQL_NO_DATA_FOUND; } /* * Copy DSN information */ STRNCPY (szDSN, sect[cur_entry << 1], cbDSNMax); if (pcbDSN) *pcbDSN = STRLEN (szDSN); /* * And find the description that goes with this entry */ STRNCPY (szDesc, sect[(cur_entry << 1) + 1], cbDescMax); if (pcbDesc) *pcbDesc = STRLEN (szDesc); /* * Next record */ cur_entry++; return SQL_SUCCESS; } SQLRETURN SQL_API SQLDataSources ( SQLHENV henv, SQLUSMALLINT fDir, SQLCHAR * szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT * pcbDSN, SQLCHAR * szDesc, SQLSMALLINT cbDescMax, SQLSMALLINT * pcbDesc) { ENTER_HENV (henv, trace_SQLDataSources (TRACE_ENTER, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); retcode = SQLDataSources_Internal ( henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc, 'A'); LEAVE_HENV (henv, trace_SQLDataSources (TRACE_LEAVE, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); } #if ODBCVER >= 0x0300 SQLRETURN SQL_API SQLDataSourcesA ( SQLHENV henv, SQLUSMALLINT fDir, SQLCHAR * szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT * pcbDSN, SQLCHAR * szDesc, SQLSMALLINT cbDescMax, SQLSMALLINT * pcbDesc) { ENTER_HENV (henv, trace_SQLDataSources (TRACE_ENTER, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); retcode = SQLDataSources_Internal( henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc, 'A'); LEAVE_HENV (henv, trace_SQLDataSources (TRACE_LEAVE, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); } SQLRETURN SQL_API SQLDataSourcesW ( SQLHENV henv, SQLUSMALLINT fDir, SQLWCHAR * szDSN, SQLSMALLINT cbDSNMax, SQLSMALLINT * pcbDSN, SQLWCHAR * szDesc, SQLSMALLINT cbDescMax, SQLSMALLINT * pcbDesc) { SQLCHAR *_DSN = NULL; SQLCHAR *_Desc = NULL; ENTER_HENV (henv, trace_SQLDataSourcesW (TRACE_ENTER, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); if (cbDSNMax > 0) { if ((_DSN = (SQLCHAR *) malloc (cbDSNMax * UTF8_MAX_CHAR_LEN + 1)) == NULL) { PUSHSQLERR (genv->herr, en_S1001); return SQL_ERROR; } } if (cbDescMax > 0) { if ((_Desc = (SQLCHAR *) malloc (cbDescMax * UTF8_MAX_CHAR_LEN + 1)) == NULL) { PUSHSQLERR (genv->herr, en_S1001); return SQL_ERROR; } } retcode = SQLDataSources_Internal ( henv, fDir, _DSN, cbDSNMax * UTF8_MAX_CHAR_LEN, pcbDSN, _Desc, cbDescMax * UTF8_MAX_CHAR_LEN, pcbDesc, 'W'); if (SQL_SUCCEEDED (retcode)) { dm_StrCopyOut2_U8toW (_DSN, szDSN, cbDSNMax, pcbDSN); dm_StrCopyOut2_U8toW (_Desc, szDesc, cbDescMax, pcbDesc); } MEM_FREE (_DSN); MEM_FREE (_Desc); LEAVE_HENV (henv, trace_SQLDataSourcesW (TRACE_LEAVE, henv, fDir, szDSN, cbDSNMax, pcbDSN, szDesc, cbDescMax, pcbDesc)); } #endif SQLRETURN SQL_API SQLDrivers_Internal ( SQLHENV henv, SQLUSMALLINT fDir, SQLPOINTER szDrvDesc, SQLSMALLINT cbDrvDescMax, SQLSMALLINT * pcbDrvDesc, SQLPOINTER szDrvAttr, SQLSMALLINT cbDrvAttrMax, SQLSMALLINT * pcbDrvAttr, SQLCHAR waMode) { GENV (genv, henv); char buffer[4096], desc[1024], *ptr; int i, j, usernum = 0; static int cur_entry = -1; static int num_entries = 0; static void **sect = NULL; SQLUSMALLINT fDirOld = fDir; waMode = waMode; /*UNUSED*/ /* check argument */ if (cbDrvDescMax < 0 || cbDrvAttrMax < 0) { PUSHSQLERR (genv->herr, en_S1090); return SQL_ERROR; } if (fDir != SQL_FETCH_FIRST && fDir != SQL_FETCH_NEXT) { PUSHSQLERR (genv->herr, en_S1103); return SQL_ERROR; } if (cur_entry < 0 || fDir == SQL_FETCH_FIRST) { cur_entry = 0; num_entries = 0; /* * Free old section list */ if (sect) { for (i = 0; i < MAX_ENTRIES; i++) if (sect[i]) free (sect[i]); free (sect); } if ((sect = (void **) calloc (MAX_ENTRIES, sizeof (void *))) == NULL) { PUSHSQLERR (genv->herr, en_S1011); return SQL_ERROR; } if (fDirOld == SQL_FETCH_FIRST) fDir = SQL_FETCH_FIRST_USER; do { SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN); SQLGetPrivateProfileString (SECT2, NULL, "", buffer, sizeof(buffer) / sizeof(SQLTCHAR), "odbcinst.ini"); /* For each datasources */ for(ptr = buffer, i = 1 ; *ptr && i ; ptr += STRLEN(ptr) + 1) { /* Add this section to the datasources list */ if (fDirOld == SQL_FETCH_FIRST && fDir == SQL_FETCH_FIRST_SYSTEM) { for(j = 0 ; j= MAX_ENTRIES) { i = 0; break; } /* Skip the rest */ /* ... and its description */ SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN); SQLGetPrivateProfileString (SECT2, ptr, "", desc, sizeof(desc) / sizeof(SQLTCHAR), "odbcinst.ini"); /* Check if the driver is installed */ if(!STRCASEEQ(desc, "Installed")) continue; /* Copy the driver name */ sect[num_entries<<1] = STRDUP (ptr); sect[(num_entries++<<1) + 1] = STRDUP (desc); } switch(fDir) { case SQL_FETCH_FIRST_USER: fDir = SQL_FETCH_FIRST_SYSTEM; usernum = num_entries; break; case SQL_FETCH_FIRST_SYSTEM: fDir = SQL_FETCH_FIRST; break; }; } while (fDir!=SQL_FETCH_FIRST && fDirOld==SQL_FETCH_FIRST); fDir = fDirOld; /* * Sort all entries so we can present a nice list */ if (num_entries > 1) { qsort (sect, num_entries, sizeof (char **) + sizeof (char **), SectSorter); } } /* * Try to get to the next item */ if (cur_entry >= num_entries) { cur_entry = 0; /* Next time, start all over again */ return SQL_NO_DATA_FOUND; } /* * Copy Driver information */ STRNCPY (szDrvDesc, sect[cur_entry << 1], cbDrvDescMax); if (pcbDrvDesc) *pcbDrvDesc = STRLEN (szDrvDesc); /* * And find the description that goes with this entry */ STRNCPY (szDrvAttr, sect[(cur_entry << 1) + 1], cbDrvAttrMax); if (pcbDrvAttr) *pcbDrvAttr = STRLEN (szDrvAttr); /* * Next record */ cur_entry++; return SQL_SUCCESS; } SQLRETURN SQL_API SQLDrivers ( SQLHENV henv, SQLUSMALLINT fDir, SQLCHAR * szDrvDesc, SQLSMALLINT cbDrvDescMax, SQLSMALLINT * pcbDrvDesc, SQLCHAR * szDrvAttr, SQLSMALLINT cbDrvAttrMax, SQLSMALLINT * pcbDrvAttr) { ENTER_HENV (henv, trace_SQLDrivers (TRACE_ENTER, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); retcode = SQLDrivers_Internal( henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr, 'A'); LEAVE_HENV (henv, trace_SQLDrivers (TRACE_LEAVE, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); } #if ODBCVER >= 0x0300 SQLRETURN SQL_API SQLDriversA ( SQLHENV henv, SQLUSMALLINT fDir, SQLCHAR * szDrvDesc, SQLSMALLINT cbDrvDescMax, SQLSMALLINT * pcbDrvDesc, SQLCHAR * szDrvAttr, SQLSMALLINT cbDrvAttrMax, SQLSMALLINT * pcbDrvAttr) { ENTER_HENV (henv, trace_SQLDrivers (TRACE_ENTER, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); retcode = SQLDrivers_Internal( henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr, 'A'); LEAVE_HENV (henv, trace_SQLDrivers (TRACE_LEAVE, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); } SQLRETURN SQL_API SQLDriversW (SQLHENV henv, SQLUSMALLINT fDir, SQLWCHAR * szDrvDesc, SQLSMALLINT cbDrvDescMax, SQLSMALLINT * pcbDrvDesc, SQLWCHAR * szDrvAttr, SQLSMALLINT cbDrvAttrMax, SQLSMALLINT * pcbDrvAttr) { SQLCHAR *_Driver = NULL; SQLCHAR *_Attrs = NULL; ENTER_HENV (henv, trace_SQLDriversW (TRACE_ENTER, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); if (cbDrvDescMax > 0) { if ((_Driver = (SQLCHAR *) malloc (cbDrvDescMax * UTF8_MAX_CHAR_LEN + 1)) == NULL) { PUSHSQLERR (genv->herr, en_S1001); return SQL_ERROR; } } if (cbDrvAttrMax > 0) { if ((_Attrs = (SQLCHAR *) malloc (cbDrvAttrMax * UTF8_MAX_CHAR_LEN + 1)) == NULL) { PUSHSQLERR (genv->herr, en_S1001); return SQL_ERROR; } } retcode = SQLDrivers_Internal ( henv, fDir, _Driver, cbDrvDescMax * UTF8_MAX_CHAR_LEN, pcbDrvDesc, _Attrs, cbDrvAttrMax * UTF8_MAX_CHAR_LEN, pcbDrvAttr, 'W'); if (SQL_SUCCEEDED (retcode)) { dm_StrCopyOut2_U8toW (_Driver, szDrvDesc, cbDrvDescMax, pcbDrvDesc); dm_StrCopyOut2_U8toW (_Attrs, szDrvAttr, cbDrvAttrMax, pcbDrvAttr); } MEM_FREE (_Driver); MEM_FREE (_Attrs); LEAVE_HENV (henv, trace_SQLDriversW (TRACE_LEAVE, henv, fDir, szDrvDesc, cbDrvDescMax, pcbDrvDesc, szDrvAttr, cbDrvAttrMax, pcbDrvAttr)); } #endif SQLRETURN SQL_API SQLGetInfo_Internal ( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue, SQLCHAR waMode) { CONN (pdbc, hdbc); ENVR (penv, pdbc->henv); STMT (pstmt, NULL); STMT (tpstmt, NULL); HPROC hproc = SQL_NULL_HPROC; SQLRETURN retcode = SQL_SUCCESS; void * _InfoValue = NULL; void * infoValueOut = rgbInfoValue; DWORD dword = 0; int size = 0, len = 0, ret = 0; wchar_t buf[20] = {'\0'}; if (cbInfoValueMax < 0) { PUSHSQLERR (pdbc->herr, en_S1090); return SQL_ERROR; } #if (ODBCVER < 0x0300) if ( /* fInfoType < SQL_INFO_FIRST || */ (fInfoType > SQL_INFO_LAST && fInfoType < SQL_INFO_DRIVER_START)) { PUSHSQLERR (pdbc->herr, en_S1096); return SQL_ERROR; } #endif if (fInfoType == SQL_ODBC_VER #if (ODBCVER >= 0x0300) || fInfoType == SQL_DM_VER #endif ) { #if (ODBCVER >= 0x0300) if (fInfoType == SQL_DM_VER) sprintf ((char*)buf, "%02d.%02d.%04d.%04d", SQL_SPEC_MAJOR, SQL_SPEC_MINOR, IODBC_BUILD / 10000, IODBC_BUILD % 10000); else #endif sprintf ((char*)buf, "%02d.%02d.0000", SQL_SPEC_MAJOR, SQL_SPEC_MINOR); if(waMode == 'W') { SQLWCHAR *prov = dm_SQL_U8toW((SQLCHAR *)buf, SQL_NTS); if(prov) { WCSNCPY(buf, prov, sizeof(buf)/sizeof(wchar_t)); free(prov); } else buf[0] = L'\0'; } if (rgbInfoValue != NULL && cbInfoValueMax > 0) { len = (waMode != 'W' ? STRLEN (buf) : WCSLEN(buf)); if (len > cbInfoValueMax - 1) { len = cbInfoValueMax - 1; PUSHSQLERR (pdbc->herr, en_01004); retcode = SQL_SUCCESS_WITH_INFO; } if (waMode != 'W') { STRNCPY (rgbInfoValue, buf, len); ((char *) rgbInfoValue)[len] = '\0'; } else { WCSNCPY (rgbInfoValue, buf, len); ((wchar_t *) rgbInfoValue)[len] = L'\0'; } } if (pcbInfoValue != NULL) { *pcbInfoValue = (SWORD) len; } return retcode; } if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata) { PUSHSQLERR (pdbc->herr, en_08003); return SQL_ERROR; } switch (fInfoType) { case SQL_DRIVER_HDBC: dword = (DWORD) (pdbc->dhdbc); size = sizeof (dword); break; case SQL_DRIVER_HENV: penv = (ENV_t *) (pdbc->henv); dword = (DWORD) (penv->dhenv); size = sizeof (dword); break; case SQL_DRIVER_HLIB: penv = (ENV_t *) (pdbc->henv); dword = (DWORD) (penv->hdll); size = sizeof (dword); break; case SQL_DRIVER_HSTMT: if (rgbInfoValue != NULL) { pstmt = *((STMT_t **) rgbInfoValue); } for (tpstmt = (STMT_t *) (pdbc->hstmt); tpstmt != NULL; tpstmt = tpstmt->next) { if (tpstmt == pstmt) { break; } } if (tpstmt == NULL) { PUSHSQLERR (pdbc->herr, en_S1009); return SQL_ERROR; } dword = (DWORD) (pstmt->dhstmt); size = sizeof (dword); break; case SQL_DRIVER_NAME: case SQL_DRIVER_ODBC_VER: case SQL_DRIVER_VER: case SQL_ODBC_INTERFACE_CONFORMANCE: break; default: /* NOTE : this was before the switch, just move here to let some information going through */ if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata) { PUSHSQLERR (pdbc->herr, en_08003); return SQL_ERROR; } } if (size) { if (rgbInfoValue != NULL) { *((DWORD *) rgbInfoValue) = dword; } if (pcbInfoValue != NULL) { *(pcbInfoValue) = (SWORD) size; } return SQL_SUCCESS; } #if (ODBCVER >= 0x0300) /* * This was a temp value in ODBC 2 */ if (((ENV_t *) pdbc->henv)->dodbc_ver == SQL_OV_ODBC2 && fInfoType == SQL_OJ_CAPABILITIES) fInfoType = 65003; #endif /* ODBCVER >= 0x0300 */ if ((penv->unicode_driver && waMode != 'W') || (!penv->unicode_driver && waMode == 'W')) { switch(fInfoType) { case SQL_ACCESSIBLE_PROCEDURES: case SQL_ACCESSIBLE_TABLES: case SQL_CATALOG_NAME: case SQL_CATALOG_NAME_SEPARATOR: case SQL_CATALOG_TERM: case SQL_COLLATION_SEQ: case SQL_COLUMN_ALIAS: case SQL_DATA_SOURCE_NAME: case SQL_DATA_SOURCE_READ_ONLY: case SQL_DATABASE_NAME: case SQL_DBMS_NAME: case SQL_DBMS_VER: case SQL_DESCRIBE_PARAMETER: case SQL_DRIVER_NAME: case SQL_DRIVER_ODBC_VER: case SQL_DRIVER_VER: case SQL_ODBC_VER: case SQL_EXPRESSIONS_IN_ORDERBY: case SQL_IDENTIFIER_QUOTE_CHAR: case SQL_INTEGRITY: case SQL_KEYWORDS: case SQL_LIKE_ESCAPE_CLAUSE: case SQL_MAX_ROW_SIZE_INCLUDES_LONG: case SQL_MULT_RESULT_SETS: case SQL_MULTIPLE_ACTIVE_TXN: case SQL_NEED_LONG_DATA_LEN: case SQL_ORDER_BY_COLUMNS_IN_SELECT: case SQL_PROCEDURE_TERM: case SQL_PROCEDURES: case SQL_ROW_UPDATES: case SQL_SCHEMA_TERM: case SQL_SEARCH_PATTERN_ESCAPE: case SQL_SERVER_NAME: case SQL_SPECIAL_CHARACTERS: case SQL_TABLE_TERM: case SQL_USER_NAME: case SQL_XOPEN_CLI_YEAR: case SQL_OUTER_JOINS: if (waMode != 'W') { /* ansi=>unicode*/ if ((_InfoValue = malloc(cbInfoValueMax * sizeof(wchar_t) + 1)) == NULL) { PUSHSQLERR (pdbc->herr, en_HY001); return SQL_ERROR; } cbInfoValueMax *= sizeof(wchar_t); } else { /* unicode=>ansi*/ if ((_InfoValue = malloc(cbInfoValueMax + 1)) == NULL) { PUSHSQLERR (pdbc->herr, en_HY001); return SQL_ERROR; } cbInfoValueMax /= sizeof(wchar_t); } infoValueOut = _InfoValue; break; } } CALL_UDRIVER(hdbc, pdbc, retcode, hproc, penv->unicode_driver, en_GetInfo, (pdbc->dhdbc, fInfoType, infoValueOut, cbInfoValueMax, pcbInfoValue)); if (hproc == SQL_NULL_HPROC) { PUSHSQLERR (pdbc->herr, en_IM001); return SQL_ERROR; } if (retcode == SQL_ERROR && fInfoType == SQL_DRIVER_ODBC_VER) { if (waMode != 'W') { STRCPY (buf, "01.00"); if (rgbInfoValue != NULL && cbInfoValueMax > 0) { len = STRLEN (buf); if (len > cbInfoValueMax - 1) { len = cbInfoValueMax - 1; ret = -1; } else { ret = 0; } STRNCPY (rgbInfoValue, buf, len); ((char *) rgbInfoValue)[len] = '\0'; } if (pcbInfoValue != NULL) *pcbInfoValue = (SWORD) len; } else { ret = dm_StrCopyOut2_A2W ((SQLCHAR *) "01.00", (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / sizeof(wchar_t), pcbInfoValue); if (pcbInfoValue) *pcbInfoValue = *pcbInfoValue * sizeof(wchar_t); } if (ret == -1) { PUSHSQLERR (pdbc->herr, en_01004); retcode = SQL_SUCCESS_WITH_INFO; } else { retcode = SQL_SUCCESS; } } else if (rgbInfoValue && SQL_SUCCEEDED (retcode) && ((penv->unicode_driver && waMode != 'W') || (!penv->unicode_driver && waMode == 'W'))) { switch(fInfoType) { case SQL_ACCESSIBLE_PROCEDURES: case SQL_ACCESSIBLE_TABLES: case SQL_CATALOG_NAME: case SQL_CATALOG_NAME_SEPARATOR: case SQL_CATALOG_TERM: case SQL_COLLATION_SEQ: case SQL_COLUMN_ALIAS: case SQL_DATA_SOURCE_NAME: case SQL_DATA_SOURCE_READ_ONLY: case SQL_DATABASE_NAME: case SQL_DBMS_NAME: case SQL_DBMS_VER: case SQL_DESCRIBE_PARAMETER: case SQL_DRIVER_NAME: case SQL_DRIVER_ODBC_VER: case SQL_DRIVER_VER: case SQL_ODBC_VER: case SQL_EXPRESSIONS_IN_ORDERBY: case SQL_IDENTIFIER_QUOTE_CHAR: case SQL_INTEGRITY: case SQL_KEYWORDS: case SQL_LIKE_ESCAPE_CLAUSE: case SQL_MAX_ROW_SIZE_INCLUDES_LONG: case SQL_MULT_RESULT_SETS: case SQL_MULTIPLE_ACTIVE_TXN: case SQL_NEED_LONG_DATA_LEN: case SQL_ORDER_BY_COLUMNS_IN_SELECT: case SQL_PROCEDURE_TERM: case SQL_PROCEDURES: case SQL_ROW_UPDATES: case SQL_SCHEMA_TERM: case SQL_SEARCH_PATTERN_ESCAPE: case SQL_SERVER_NAME: case SQL_SPECIAL_CHARACTERS: case SQL_TABLE_TERM: case SQL_USER_NAME: case SQL_XOPEN_CLI_YEAR: case SQL_OUTER_JOINS: if (waMode != 'W') { /* ansi<=unicode*/ ret = dm_StrCopyOut2_W2A ((SQLWCHAR *) infoValueOut, (SQLCHAR *) rgbInfoValue, cbInfoValueMax / sizeof(wchar_t), pcbInfoValue); } else { /* unicode<=ansi*/ ret = dm_StrCopyOut2_A2W ((SQLCHAR *) infoValueOut, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax, pcbInfoValue); if (pcbInfoValue) *pcbInfoValue = *pcbInfoValue * sizeof(wchar_t); } if (ret == -1) { PUSHSQLERR (pdbc->herr, en_01004); retcode = SQL_SUCCESS_WITH_INFO; } break; } } MEM_FREE(_InfoValue); return retcode; } SQLRETURN SQL_API SQLGetInfo (SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue) { ENTER_HDBC (hdbc, 0, trace_SQLGetInfo (TRACE_ENTER, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); retcode = SQLGetInfo_Internal( hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue, 'A'); LEAVE_HDBC (hdbc, 0, trace_SQLGetInfo (TRACE_LEAVE, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); } #if ODBCVER >= 0x0300 SQLRETURN SQL_API SQLGetInfoA (SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue) { ENTER_HDBC (hdbc, 0, trace_SQLGetInfo (TRACE_ENTER, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); retcode = SQLGetInfo_Internal( hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue, 'A'); LEAVE_HDBC (hdbc, 0, trace_SQLGetInfo (TRACE_LEAVE, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); } SQLRETURN SQL_API SQLGetInfoW ( SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue) { ENTER_HDBC (hdbc, 0, trace_SQLGetInfoW (TRACE_ENTER, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); retcode = SQLGetInfo_Internal ( hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue, 'W'); LEAVE_HDBC (hdbc, 0, trace_SQLGetInfoW (TRACE_LEAVE, hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue)); } #endif static int FunctionNumbers[] = { 0 #define FUNCDEF(A,B,C) ,A #include "henv.ci" #undef FUNCDEF }; #if (ODBCVER >= 0x0300) #define SQL_ODBC3_SET_FUNC_ON(pfExists, uwAPI) \ *( ((UWORD*) (pfExists)) + ((uwAPI) >> 4) ) |= (1 << ((uwAPI) & 0x000F)) #define SQL_ODBC3_SET_FUNC_OFF(pfExists, uwAPI) \ *( ((UWORD*) (pfExists)) + ((uwAPI) >> 4) ) &= !(1 << ((uwAPI) & 0x000F)) #endif static SQLRETURN SQLGetFunctions_Internal ( SQLHDBC hdbc, SQLUSMALLINT fFunc, SQLUSMALLINT * pfExists) { CONN (pdbc, hdbc); HPROC hproc; SQLRETURN retcode; int i; UWORD functions2[100]; #if (ODBCVER >= 0x0300) UWORD functions3[SQL_API_ODBC3_ALL_FUNCTIONS_SIZE]; #endif if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata) { PUSHSQLERR (pdbc->herr, en_S1010); return SQL_ERROR; } if (pfExists == NULL) { return SQL_SUCCESS; } /* * These functions are supported by the iODBC driver manager */ if (fFunc == SQL_API_SQLDATASOURCES || fFunc == SQL_API_SQLDRIVERS #if (ODBCVER >= 0x0300) || fFunc == SQL_API_SQLGETENVATTR || fFunc == SQL_API_SQLSETENVATTR #endif ) { *pfExists = (UWORD) 1; return SQL_SUCCESS; } /* * Check if function number is within ODBC version context */ #if (ODBCVER < 0x0300) if (fFunc > SQL_EXT_API_LAST) { PUSHSQLERR (pdbc->herr, en_S1095); return SQL_ERROR; } #endif /* * In a ODBC 2.x driver context, the ODBC 3.x API calls are * mapped by the driver manager. */ #if (ODBCVER >= 0x0300) if (((ENV_t *) pdbc->henv)->dodbc_ver == SQL_OV_ODBC2) { switch (fFunc) { case SQL_API_ALL_FUNCTIONS: case SQL_API_ODBC3_ALL_FUNCTIONS: break; /* Mapped ODBC3 app -> ODBC2 driver functions */ case SQL_API_SQLALLOCHANDLE: case SQL_API_SQLFREEHANDLE: case SQL_API_SQLSETCONNECTATTR: case SQL_API_SQLGETCONNECTATTR: case SQL_API_SQLGETSTMTATTR: case SQL_API_SQLSETSTMTATTR: case SQL_API_SQLCOLATTRIBUTE: case SQL_API_SQLENDTRAN: case SQL_API_SQLBULKOPERATIONS: case SQL_API_SQLFETCHSCROLL: case SQL_API_SQLGETDIAGREC: case SQL_API_SQLGETDIAGFIELD: *pfExists = SQL_TRUE; return SQL_SUCCESS; case SQL_API_SQLBINDPARAM: fFunc = SQL_API_SQLBINDPARAMETER; break; default: if (fFunc > SQL_API_SQLBINDPARAMETER) { *pfExists = SQL_FALSE; return SQL_SUCCESS; } break; } } #endif /* * If the driver exports a SQLGetFunctions call, use it */ hproc = _iodbcdm_getproc (pdbc, en_GetFunctions); if (hproc != SQL_NULL_HPROC) { CALL_DRIVER (hdbc, pdbc, retcode, hproc, (pdbc->dhdbc, fFunc, pfExists)); return retcode; } /* * Map deprecated functions */ if (fFunc == SQL_API_SQLSETPARAM) { fFunc = SQL_API_SQLBINDPARAMETER; } /* * Initialize intermediate result arrays */ memset (functions2, '\0', sizeof (functions2)); #if (ODBCVER > 0x0300) memset (functions3, '\0', sizeof (functions3)); #endif /* * Build result array by scanning for all API calls */ for (i = 1; i < __LAST_API_FUNCTION__; i++) { int j = FunctionNumbers[i]; hproc = _iodbcdm_getproc (pdbc, i); if (hproc != SQL_NULL_HPROC) { if (j < 100) functions2[j] = 1; #if (ODBCVER >= 0x0300) functions3[j >> 4] |= (1 << (j & 0x000F)); #endif } } /* * Finally return the information */ if (fFunc == SQL_API_ALL_FUNCTIONS) { memcpy (pfExists, &functions2, sizeof (functions2)); } #if (ODBCVER < 0x0300) else { *pfExists = functions2[fFunc]; } #else else if (fFunc == SQL_API_ODBC3_ALL_FUNCTIONS) { memcpy (pfExists, &functions3, sizeof (functions3)); } else { *pfExists = SQL_FUNC_EXISTS (functions3, fFunc); } #endif return SQL_SUCCESS; } SQLRETURN SQL_API SQLGetFunctions ( SQLHDBC hdbc, SQLUSMALLINT fFunc, SQLUSMALLINT * pfExists) { ENTER_HDBC (hdbc, 0, trace_SQLGetFunctions (TRACE_ENTER, hdbc, fFunc, pfExists)); retcode = SQLGetFunctions_Internal ( hdbc, fFunc, pfExists); LEAVE_HDBC (hdbc, 0, trace_SQLGetFunctions (TRACE_LEAVE, hdbc, fFunc, pfExists)); }