LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLSpecialColumns.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 110 0.0 %
Date: 2021-10-13 02:24:04 Functions: 0 1 0.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * This code was created by Peter Harvey (mostly during Christmas 98/99).
      11             :  * This code is LGPL. Please ensure that this message remains in future
      12             :  * distributions and uses of this code (thats about all I get out of it).
      13             :  * - Peter Harvey pharvey@codebydesign.com
      14             :  *
      15             :  * This file has been modified for the MonetDB project.  See the file
      16             :  * Copyright in this directory for more information.
      17             :  */
      18             : 
      19             : /**********************************************************************
      20             :  * SQLSpecialColumns()
      21             :  * CLI Compliance: X/Open
      22             :  *
      23             :  * Author: Martin van Dinther, Sjoerd Mullender
      24             :  * Date  : 30 aug 2002
      25             :  *
      26             :  **********************************************************************/
      27             : 
      28             : #include "ODBCGlobal.h"
      29             : #include "ODBCStmt.h"
      30             : #include "ODBCUtil.h"
      31             : #include "ODBCQueries.h"
      32             : 
      33             : 
      34             : #ifdef ODBCDEBUG
      35             : static char *
      36             : translateIdentifierType(SQLUSMALLINT IdentifierType)
      37             : {
      38           0 :         switch (IdentifierType) {
      39             :         case SQL_BEST_ROWID:
      40             :                 return "SQL_BEST_ROWID";
      41           0 :         case SQL_ROWVER:
      42           0 :                 return "SQL_ROWVER";
      43           0 :         default:
      44           0 :                 return "unknown";
      45             :         }
      46             : }
      47             : 
      48             : static char *
      49             : translateScope(SQLUSMALLINT Scope)
      50             : {
      51             :         /* check for valid Scope argument */
      52           0 :         switch (Scope) {
      53             :         case SQL_SCOPE_CURROW:
      54             :                 return "SQL_SCOPE_CURROW";
      55           0 :         case SQL_SCOPE_TRANSACTION:
      56           0 :                 return "SQL_SCOPE_TRANSACTION";
      57           0 :         case SQL_SCOPE_SESSION:
      58           0 :                 return "SQL_SCOPE_SESSION";
      59           0 :         default:
      60           0 :                 return "unknown";
      61             :         }
      62             : }
      63             : 
      64             : static char *
      65             : translateNullable(SQLUSMALLINT Nullable)
      66             : {
      67             :         /* check for valid Nullable argument */
      68           0 :         switch (Nullable) {
      69             :         case SQL_NO_NULLS:
      70             :                 return "SQL_NO_NULLS";
      71           0 :         case SQL_NULLABLE:
      72           0 :                 return "SQL_NULLABLE";
      73           0 :         default:
      74           0 :                 return "unknown";
      75             :         }
      76             : }
      77             : #endif
      78             : 
      79             : static SQLRETURN
      80           0 : MNDBSpecialColumns(ODBCStmt *stmt,
      81             :                    SQLUSMALLINT IdentifierType,
      82             :                    const SQLCHAR *CatalogName,
      83             :                    SQLSMALLINT NameLength1,
      84             :                    const SQLCHAR *SchemaName,
      85             :                    SQLSMALLINT NameLength2,
      86             :                    const SQLCHAR *TableName,
      87             :                    SQLSMALLINT NameLength3,
      88             :                    SQLUSMALLINT Scope,
      89             :                    SQLUSMALLINT Nullable)
      90             : {
      91             :         RETCODE rc;
      92             : 
      93             :         /* buffer for the constructed query to do meta data retrieval */
      94             :         char *query = NULL;
      95             :         size_t querylen;
      96             :         size_t pos = 0;
      97             :         char *sch = NULL, *tab = NULL;
      98             : 
      99           0 :         fixODBCstring(CatalogName, NameLength1, SQLSMALLINT, addStmtError, stmt, return SQL_ERROR);
     100           0 :         fixODBCstring(SchemaName, NameLength2, SQLSMALLINT, addStmtError, stmt, return SQL_ERROR);
     101           0 :         fixODBCstring(TableName, NameLength3, SQLSMALLINT, addStmtError, stmt, return SQL_ERROR);
     102             : 
     103             : #ifdef ODBCDEBUG
     104           0 :         ODBCLOG("\"%.*s\" \"%.*s\" \"%.*s\" %s %s\n",
     105             :                 (int) NameLength1, CatalogName ? (char *) CatalogName : "",
     106             :                 (int) NameLength2, SchemaName ? (char *) SchemaName : "",
     107             :                 (int) NameLength3, TableName ? (char *) TableName : "",
     108             :                 translateScope(Scope), translateNullable(Nullable));
     109             : #endif
     110             : 
     111             :         /* check for valid IdentifierType argument */
     112           0 :         switch (IdentifierType) {
     113             :         case SQL_BEST_ROWID:
     114             :         case SQL_ROWVER:
     115             :                 break;
     116           0 :         default:
     117             :                 /* Column type out of range */
     118           0 :                 addStmtError(stmt, "HY097", NULL, 0);
     119           0 :                 return SQL_ERROR;
     120             :         }
     121             : 
     122             :         /* check for valid Scope argument */
     123           0 :         switch (Scope) {
     124             :         case SQL_SCOPE_CURROW:
     125             :         case SQL_SCOPE_TRANSACTION:
     126             :         case SQL_SCOPE_SESSION:
     127             :                 break;
     128           0 :         default:
     129             :                 /* Scope type out of range */
     130           0 :                 addStmtError(stmt, "HY098", NULL, 0);
     131           0 :                 return SQL_ERROR;
     132             :         }
     133             : 
     134             :         /* check for valid Nullable argument */
     135           0 :         switch (Nullable) {
     136             :         case SQL_NO_NULLS:
     137             :         case SQL_NULLABLE:
     138             :                 break;
     139           0 :         default:
     140             :                 /* Nullable type out of range */
     141           0 :                 addStmtError(stmt, "HY099", NULL, 0);
     142           0 :                 return SQL_ERROR;
     143             :         }
     144             : 
     145             :         /* check if a valid (non null, not empty) table name is supplied */
     146           0 :         if (TableName == NULL) {
     147             :                 /* Invalid use of null pointer */
     148           0 :                 addStmtError(stmt, "HY009", NULL, 0);
     149           0 :                 return SQL_ERROR;
     150             :         }
     151           0 :         if (NameLength3 == 0) {
     152             :                 /* Invalid string or buffer length */
     153           0 :                 addStmtError(stmt, "HY090", NULL, 0);
     154           0 :                 return SQL_ERROR;
     155             :         }
     156             : 
     157             :         /* SQLSpecialColumns returns a table with the following columns:
     158             :            SMALLINT     scope
     159             :            VARCHAR      column_name NOT NULL
     160             :            SMALLINT     data_type NOT NULL
     161             :            VARCHAR      type_name NOT NULL
     162             :            INTEGER      column_size
     163             :            INTEGER      buffer_length
     164             :            SMALLINT     decimal_digits
     165             :            SMALLINT     pseudo_column
     166             :          */
     167           0 :         if (IdentifierType == SQL_BEST_ROWID) {
     168             :                 /* Select from the key table the (smallest) primary/unique key */
     169           0 :                 if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
     170           0 :                         if (NameLength2 > 0) {
     171           0 :                                 sch = ODBCParseOA("s", "name",
     172             :                                                   (const char *) SchemaName,
     173             :                                                   (size_t) NameLength2);
     174           0 :                                 if (sch == NULL)
     175           0 :                                         goto nomem;
     176             :                         }
     177           0 :                         if (NameLength3 > 0) {
     178           0 :                                 tab = ODBCParseOA("t", "name",
     179             :                                                   (const char *) TableName,
     180             :                                                   (size_t) NameLength3);
     181           0 :                                 if (tab == NULL)
     182           0 :                                         goto nomem;
     183             :                         }
     184             :                 } else {
     185           0 :                         if (NameLength2 > 0) {
     186           0 :                                 sch = ODBCParseID("s", "name",
     187             :                                                   (const char *) SchemaName,
     188             :                                                   (size_t) NameLength2);
     189           0 :                                 if (sch == NULL)
     190           0 :                                         goto nomem;
     191             :                         }
     192           0 :                         if (NameLength3 > 0) {
     193           0 :                                 tab = ODBCParseID("t", "name",
     194             :                                                   (const char *) TableName,
     195             :                                                   (size_t) NameLength3);
     196           0 :                                 if (tab == NULL)
     197           0 :                                         goto nomem;
     198             :                         }
     199             :                 }
     200             : 
     201             :                 /* first create a string buffer (1000 extra bytes is plenty */
     202           0 :                 querylen = 5000 + NameLength1 + NameLength2 + NameLength3;
     203           0 :                 query = malloc(querylen);
     204           0 :                 if (query == NULL)
     205           0 :                         goto nomem;
     206             : 
     207             :                 /* Note: SCOPE is SQL_SCOPE_TRANSACTION */
     208             :                 /* Note: PSEUDO_COLUMN is SQL_PC_NOT_PSEUDO */
     209           0 :                 pos += snprintf(query + pos, querylen - pos,
     210             :                         "with sc as ("
     211             :                         "select t.id as table_id, k.type as type, "
     212             :                                "cast(%d as smallint) as scope, "
     213             :                                "c.name as column_name, "
     214             :                         DATA_TYPE(c) ", "
     215             :                         TYPE_NAME(c) ", "
     216             :                         COLUMN_SIZE(c) ", "
     217             :                         BUFFER_LENGTH(c) ", "
     218             :                         DECIMAL_DIGITS(c) ", "
     219             :                                "cast(%d as smallint) as pseudo_column "
     220             :                          "from sys.schemas s, "
     221             :                               "sys.tables t, "
     222             :                               "sys.columns c, "
     223             :                               "sys.keys k, "
     224             :                               "sys.objects kc "
     225             :                          "where s.id = t.schema_id and "
     226             :                                "t.id = c.table_id and "
     227             :                                "t.id = k.table_id and "
     228             :                                "c.name = kc.name and "
     229             :                                "kc.id = k.id and "
     230             :                                "k.type = 0",
     231             :                         /* scope: */
     232             :                         SQL_SCOPE_TRANSACTION,
     233             : #ifdef DATA_TYPE_ARGS
     234             :                         DATA_TYPE_ARGS,
     235             : #endif
     236             : #ifdef TYPE_NAME_ARGS
     237             :                         TYPE_NAME_ARGS,
     238             : #endif
     239             : #ifdef COLUMN_SIZE_ARGS
     240             :                         COLUMN_SIZE_ARGS,
     241             : #endif
     242             : #ifdef BUFFER_SIZE_ARGS
     243             :                         BUFFER_SIZE_ARGS,
     244             : #endif
     245             : #ifdef DECIMAL_DIGITS_ARGS
     246             :                         DECIMAL_DIGITS_ARGS,
     247             : #endif
     248             :                         /* pseudo_column: */
     249             :                         SQL_PC_NOT_PSEUDO);
     250           0 :                 assert(pos < 4300);
     251             :                 /* TODO: improve the SQL to get the correct result:
     252             :                    - only one set of columns should be returned, also
     253             :                      when multiple primary keys are available for this
     254             :                      table.
     255             :                    - when the table has NO primary key it should
     256             :                      return the columns of a unique key (only from ONE
     257             :                      unique key which is also the best/smallest key)
     258             :                    TODO: optimize SQL:
     259             :                    - when no SchemaName is set (see above) also no
     260             :                      filtering on SCHEMA NAME and join with table
     261             :                      SCHEMAS is needed!
     262             :                  */
     263             : 
     264             :                 /* add the selection condition */
     265           0 :                 if (NameLength1 > 0 && CatalogName != NULL) {
     266             :                         /* filtering requested on catalog name */
     267           0 :                         if (strcmp((char *) CatalogName, stmt->Dbc->dbname) != 0) {
     268             :                                 /* catalog name does not match the database name, so return no rows */
     269           0 :                                 pos += snprintf(query + pos, querylen - pos, " and 1=2");
     270             :                         }
     271             :                 }
     272           0 :                 if (sch) {
     273             :                         /* filtering requested on schema name */
     274           0 :                         pos += snprintf(query + pos, querylen - pos, " and %s", sch);
     275           0 :                         free(sch);
     276             :                 }
     277           0 :                 if (tab) {
     278             :                         /* filtering requested on table name */
     279           0 :                         pos += snprintf(query + pos, querylen - pos, " and %s", tab);
     280           0 :                         free(tab);
     281             :                 }
     282             : 
     283             :                 /* add an extra selection when SQL_NO_NULLS is requested */
     284           0 :                 if (Nullable == SQL_NO_NULLS) {
     285           0 :                         pos += strcpy_len(query + pos, " and c.\"null\" = false", querylen - pos);
     286             :                 }
     287             : 
     288           0 :                 pos += strcpy_len(query + pos,
     289             :                        "), "
     290             :                         "tid as ("
     291             :                            "select t.id as tid "
     292             :                             "from sys._tables t, sys.keys k "
     293             :                             "where t.id = k.table_id and k.type = 0"
     294             :                        ") "
     295             :                         "select sc.scope, sc.column_name, sc.data_type, "
     296             :                                "sc.type_name, sc.column_size, "
     297             :                                "sc.buffer_length, sc.decimal_digits, "
     298             :                                "sc.pseudo_column "
     299             :                         "from sc "
     300             :                         "where (sc.type = 0 and "
     301             :                                "sc.table_id in (select tid from tid)) or "
     302             :                               "(sc.type = 1 and "
     303             :                                "sc.table_id not in (select tid from tid))",
     304             :                         querylen - pos);
     305             : 
     306             :                 /* ordering on SCOPE not needed (since it is constant) */
     307             :         } else {
     308           0 :                 assert(IdentifierType == SQL_ROWVER);
     309             :                 /* The backend does not have such info available */
     310             :                 /* create just a query which results in zero rows */
     311             :                 /* Note: pseudo_column is sql_pc_unknown is 0 */
     312           0 :                 query = strdup("select cast(null as smallint) as scope, "
     313             :                                       "cast('' as varchar(1)) as column_name, "
     314             :                                       "cast(1 as smallint) as data_type, "
     315             :                                       "cast('char' as varchar(4)) as type_name, "
     316             :                                       "cast(1 as integer) as column_size, "
     317             :                                       "cast(1 as integer) as buffer_length, "
     318             :                                       "cast(0 as smallint) as decimal_digits, "
     319             :                                       "cast(0 as smallint) as pseudo_column "
     320             :                                "where 0 = 1");
     321           0 :                 if (query == NULL)
     322           0 :                         goto nomem;
     323           0 :                 pos = strlen(query);
     324             :         }
     325             : 
     326             :         /* query the MonetDB data dictionary tables */
     327           0 :         rc = MNDBExecDirect(stmt, (SQLCHAR *) query, (SQLINTEGER) pos);
     328             : 
     329           0 :         free(query);
     330             : 
     331           0 :         return rc;
     332             : 
     333           0 :   nomem:
     334             :         /* note that query must be NULL when we get here */
     335           0 :         if (sch)
     336           0 :                 free(sch);
     337           0 :         if (tab)
     338           0 :                 free(tab);
     339             :         /* Memory allocation error */
     340           0 :         addStmtError(stmt, "HY001", NULL, 0);
     341           0 :         return SQL_ERROR;
     342             : }
     343             : 
     344             : SQLRETURN SQL_API
     345             : SQLSpecialColumns(SQLHSTMT StatementHandle,
     346             :                   SQLUSMALLINT IdentifierType,
     347             :                   SQLCHAR *CatalogName,
     348             :                   SQLSMALLINT NameLength1,
     349             :                   SQLCHAR *SchemaName,
     350             :                   SQLSMALLINT NameLength2,
     351             :                   SQLCHAR *TableName,
     352             :                   SQLSMALLINT NameLength3,
     353             :                   SQLUSMALLINT Scope,
     354             :                   SQLUSMALLINT Nullable)
     355             : {
     356             :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     357             : 
     358             : #ifdef ODBCDEBUG
     359           0 :         ODBCLOG("SQLSpecialColumns %p %s ",
     360             :                 StatementHandle,
     361             :                 translateIdentifierType(IdentifierType));
     362             : #endif
     363             : 
     364           0 :         if (!isValidStmt(stmt))
     365             :                  return SQL_INVALID_HANDLE;
     366             : 
     367           0 :         clearStmtErrors(stmt);
     368             : 
     369           0 :         return MNDBSpecialColumns(stmt,
     370             :                                   IdentifierType,
     371             :                                   CatalogName, NameLength1,
     372             :                                   SchemaName, NameLength2,
     373             :                                   TableName, NameLength3,
     374             :                                   Scope,
     375             :                                   Nullable);
     376             : }
     377             : 
     378             : SQLRETURN SQL_API
     379             : SQLSpecialColumnsA(SQLHSTMT StatementHandle,
     380             :                    SQLUSMALLINT IdentifierType,
     381             :                    SQLCHAR *CatalogName,
     382             :                    SQLSMALLINT NameLength1,
     383             :                    SQLCHAR *SchemaName,
     384             :                    SQLSMALLINT NameLength2,
     385             :                    SQLCHAR *TableName,
     386             :                    SQLSMALLINT NameLength3,
     387             :                    SQLUSMALLINT Scope,
     388             :                    SQLUSMALLINT Nullable)
     389             : {
     390           0 :         return SQLSpecialColumns(StatementHandle,
     391             :                                  IdentifierType,
     392             :                                  CatalogName, NameLength1,
     393             :                                  SchemaName, NameLength2,
     394             :                                  TableName, NameLength3,
     395             :                                  Scope,
     396             :                                  Nullable);
     397             : }
     398             : 
     399             : SQLRETURN SQL_API
     400             : SQLSpecialColumnsW(SQLHSTMT StatementHandle,
     401             :                    SQLUSMALLINT IdentifierType,
     402             :                    SQLWCHAR *CatalogName,
     403             :                    SQLSMALLINT NameLength1,
     404             :                    SQLWCHAR *SchemaName,
     405             :                    SQLSMALLINT NameLength2,
     406             :                    SQLWCHAR *TableName,
     407             :                    SQLSMALLINT NameLength3,
     408             :                    SQLUSMALLINT Scope,
     409             :                    SQLUSMALLINT Nullable)
     410             : {
     411             :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     412             :         SQLRETURN rc = SQL_ERROR;
     413             :         SQLCHAR *catalog = NULL, *schema = NULL, *table = NULL;
     414             : 
     415             : #ifdef ODBCDEBUG
     416           0 :         ODBCLOG("SQLSpecialColumnsW %p %s ",
     417             :                 StatementHandle,
     418             :                 translateIdentifierType(IdentifierType));
     419             : #endif
     420             : 
     421           0 :         if (!isValidStmt(stmt))
     422             :                  return SQL_INVALID_HANDLE;
     423             : 
     424           0 :         clearStmtErrors(stmt);
     425             : 
     426           0 :         fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
     427             :                    addStmtError, stmt, goto bailout);
     428           0 :         fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
     429             :                    addStmtError, stmt, goto bailout);
     430           0 :         fixWcharIn(TableName, NameLength3, SQLCHAR, table,
     431             :                    addStmtError, stmt, goto bailout);
     432             : 
     433           0 :         rc = MNDBSpecialColumns(stmt,
     434             :                                 IdentifierType,
     435             :                                 catalog, SQL_NTS,
     436             :                                 schema, SQL_NTS,
     437             :                                 table, SQL_NTS,
     438             :                                 Scope,
     439             :                                 Nullable);
     440             : 
     441           0 :       bailout:
     442           0 :         if (catalog)
     443           0 :                 free(catalog);
     444           0 :         if (schema)
     445           0 :                 free(schema);
     446           0 :         if (table)
     447           0 :                 free(table);
     448             : 
     449             :         return rc;
     450             : }

Generated by: LCOV version 1.14