LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLTables.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 90 137 65.7 %
Date: 2024-10-03 20:03:20 Functions: 1 1 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             :  * SQLTables()
      25             :  * CLI Compliance: X/Open
      26             :  *
      27             :  * Author: Martin van Dinther, Sjoerd Mullender
      28             :  * Date  : 30 aug 2002
      29             :  *
      30             :  **********************************************************************/
      31             : 
      32             : #include "ODBCGlobal.h"
      33             : #include "ODBCStmt.h"
      34             : #include "ODBCUtil.h"
      35             : 
      36             : static SQLRETURN
      37           9 : MNDBTables(ODBCStmt *stmt,
      38             :            const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
      39             :            const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
      40             :            const SQLCHAR *TableName, SQLSMALLINT NameLength3,
      41             :            const SQLCHAR *TableType, SQLSMALLINT NameLength4)
      42             : {
      43           9 :         RETCODE rc;
      44           9 :         char *sch = NULL, *tab = NULL;
      45             : 
      46             :         /* buffer for the constructed query to do meta data retrieval */
      47           9 :         char *query = NULL;
      48           9 :         size_t pos = 0;
      49             : 
      50             :         /* convert input string parameters to normal null terminated C
      51             :          * strings */
      52           9 :         fixODBCstring(CatalogName, NameLength1, SQLSMALLINT,
      53             :                       addStmtError, stmt, return SQL_ERROR);
      54           9 :         fixODBCstring(SchemaName, NameLength2, SQLSMALLINT,
      55             :                       addStmtError, stmt, return SQL_ERROR);
      56           9 :         fixODBCstring(TableName, NameLength3, SQLSMALLINT,
      57             :                       addStmtError, stmt, return SQL_ERROR);
      58           9 :         fixODBCstring(TableType, NameLength4, SQLSMALLINT,
      59             :                       addStmtError, stmt, return SQL_ERROR);
      60             : 
      61             : #ifdef ODBCDEBUG
      62          11 :         ODBCLOG("\"%.*s\" \"%.*s\" \"%.*s\" \"%.*s\"\n",
      63             :                 (int) NameLength1, CatalogName ? (char *) CatalogName : "",
      64             :                 (int) NameLength2, SchemaName ? (char *) SchemaName : "",
      65             :                 (int) NameLength3, TableName ? (char *) TableName : "",
      66             :                 (int) NameLength4, TableType ? (char *) TableType : "");
      67             : #endif
      68             : 
      69             :         /* SQLTables returns a table with the following columns:
      70             :            VARCHAR      TABLE_CAT
      71             :            VARCHAR      TABLE_SCHEM
      72             :            VARCHAR      TABLE_NAME
      73             :            VARCHAR      TABLE_TYPE
      74             :            VARCHAR      REMARKS
      75             :          */
      76             : 
      77             :         /* Check first on the special cases */
      78           9 :         if (NameLength2 == 0 &&
      79           2 :             NameLength3 == 0 &&
      80           2 :             CatalogName &&
      81           2 :             strcmp((char *) CatalogName, SQL_ALL_CATALOGS) == 0) {
      82             :                 /* Special case query to fetch all Catalog names. */
      83             :                 /* All columns except the TABLE_CAT column contain NULLs. */
      84           1 :                 query = strdup("select cast(null as varchar(1)) as \"TABLE_CAT\", "
      85             :                                       "cast(null as varchar(1)) as \"TABLE_SCHEM\", "
      86             :                                       "cast(null as varchar(1)) as \"TABLE_NAME\", "
      87             :                                       "cast(null as varchar(1)) as \"TABLE_TYPE\", "
      88             :                                       "cast(null as varchar(1)) as \"REMARKS\" "
      89             :                                "where 1=2");  /* return no rows */
      90           1 :                 if (query == NULL)
      91           0 :                         goto nomem;
      92           8 :         } else if (NameLength1 == 0 &&
      93           2 :                    NameLength3 == 0 &&
      94           2 :                    SchemaName &&
      95           2 :                    strcmp((char *) SchemaName, SQL_ALL_SCHEMAS) == 0) {
      96             :                 /* Special case query to fetch all Schema names. */
      97             :                 /* All columns except the TABLE_SCHEM column contain NULLs. */
      98           1 :                 query = strdup("select cast(null as varchar(1)) as \"TABLE_CAT\", "
      99             :                                       "name as \"TABLE_SCHEM\", "
     100             :                                       "cast(null as varchar(1)) as \"TABLE_NAME\", "
     101             :                                       "cast(null as varchar(1)) as \"TABLE_TYPE\", "
     102             :                                /* ODBC says remarks column contains
     103             :                                 * NULL even though MonetDB supports
     104             :                                 * schema remarks. We must comply with ODBC */
     105             :                                       "cast(null as varchar(1)) as \"REMARKS\" "
     106             :                                "from sys.schemas order by \"TABLE_SCHEM\"");
     107           1 :                 if (query == NULL)
     108           0 :                         goto nomem;
     109           7 :         } else if (NameLength1 == 0 &&
     110           7 :                    NameLength2 == 0 &&
     111           1 :                    NameLength3 == 0 &&
     112           1 :                    TableType &&
     113           1 :                    strcmp((char *) TableType, SQL_ALL_TABLE_TYPES) == 0) {
     114             :                 /* Special case query to fetch all Table type names. */
     115             :                 /* All columns except the TABLE_TYPE column contain NULLs. */
     116           1 :                 query = strdup("select cast(null as varchar(1)) as \"TABLE_CAT\", "
     117             :                                       "cast(null as varchar(1)) as \"TABLE_SCHEM\", "
     118             :                                       "cast(null as varchar(1)) as \"TABLE_NAME\", "
     119             :                                       "table_type_name as \"TABLE_TYPE\", "
     120             :                                       "cast(null as varchar(1)) as \"REMARKS\" "
     121             :                                "from sys.table_types order by \"TABLE_TYPE\"");
     122           1 :                 if (query == NULL)
     123           0 :                         goto nomem;
     124             :         } else {
     125             :                 /* no special case argument values */
     126           6 :                 size_t querylen;
     127             : 
     128           6 :                 if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
     129           6 :                         if (NameLength2 > 0) {
     130           6 :                                 sch = ODBCParsePV("s", "name",
     131             :                                                   (const char *) SchemaName,
     132             :                                                   (size_t) NameLength2,
     133             :                                                   stmt->Dbc);
     134           6 :                                 if (sch == NULL)
     135           0 :                                         goto nomem;
     136             :                         }
     137           6 :                         if (NameLength3 > 0) {
     138          12 :                                 tab = ODBCParsePV("t", "name",
     139             :                                                   (const char *) TableName,
     140             :                                                   (size_t) NameLength3,
     141           6 :                                                   stmt->Dbc);
     142           6 :                                 if (tab == NULL)
     143           0 :                                         goto nomem;
     144             :                         }
     145             :                 } else {
     146           0 :                         if (NameLength2 > 0) {
     147           0 :                                 sch = ODBCParseID("s", "name",
     148             :                                                   (const char *) SchemaName,
     149             :                                                   (size_t) NameLength2);
     150           0 :                                 if (sch == NULL)
     151           0 :                                         goto nomem;
     152             :                         }
     153           0 :                         if (NameLength3 > 0) {
     154           0 :                                 tab = ODBCParseID("t", "name",
     155             :                                                   (const char *) TableName,
     156             :                                                   (size_t) NameLength3);
     157           0 :                                 if (tab == NULL)
     158           0 :                                         goto nomem;
     159             :                         }
     160             :                 }
     161             : 
     162             :                 /* construct the query now */
     163           6 :                 querylen = 2000 +
     164           6 :                         (sch ? strlen(sch) : 0) + (tab ? strlen(tab) : 0) +
     165           6 :                         ((NameLength4 + 1) / 5) * 67;
     166           6 :                 query = malloc(querylen);
     167           6 :                 if (query == NULL)
     168           0 :                         goto nomem;
     169             : 
     170           6 :                 pos += snprintf(query + pos, querylen - pos,
     171             :                        "select cast(null as varchar(1)) as \"TABLE_CAT\", "
     172             :                               "s.name as \"TABLE_SCHEM\", "
     173             :                               "t.name as \"TABLE_NAME\", "
     174             :                               "tt.table_type_name as \"TABLE_TYPE\", "
     175             :                               "%s as \"REMARKS\" "
     176             :                        "from sys.schemas s, "
     177             :                             "sys.tables t%s, "
     178             :                             "sys.table_types tt "
     179             :                        "where s.id = t.schema_id and "
     180             :                              "t.type = tt.table_type_id",
     181             :                         stmt->Dbc->has_comment ? "c.remark" : "cast(null as varchar(1))",
     182           6 :                         stmt->Dbc->has_comment ? " left outer join sys.comments c on c.id = t.id" : "");
     183           6 :                 assert(pos < 1900);
     184             : 
     185             :                 /* dependent on the input parameter values we must add a
     186             :                    variable selection condition dynamically */
     187             : 
     188             :                 /* Construct the selection condition query part */
     189           6 :                 if (NameLength1 > 0 && CatalogName != NULL) {
     190             :                         /* filtering requested on catalog name */
     191           0 :                         if (strcmp((char *) CatalogName, msetting_string(stmt->Dbc->settings, MP_DATABASE)) != 0) {
     192             :                                 /* catalog name does not match the database name, so return no rows */
     193           0 :                                 pos += snprintf(query + pos, querylen - pos, " and 1=2");
     194             :                         }
     195             :                 }
     196           6 :                 if (sch) {
     197             :                         /* filtering requested on schema name */
     198           6 :                         pos += snprintf(query + pos, querylen - pos, " and %s", sch);
     199           6 :                         free(sch);
     200             :                 }
     201           6 :                 if (tab) {
     202             :                         /* filtering requested on table name */
     203           6 :                         pos += snprintf(query + pos, querylen - pos, " and %s", tab);
     204           6 :                         free(tab);
     205             :                 }
     206             : 
     207           6 :                 if (NameLength4 > 0) {
     208             :                         /* filtering requested on table type(s)
     209             :                          * each table type can be enclosed in single quotation marks (')
     210             :                          * or unquoted, for example, 'TABLE', 'VIEW' or TABLE, VIEW.
     211             :                          */
     212           5 :                         char buf[32];   /* the longest string is "GLOBAL TEMPORARY TABLE" */
     213           5 :                         int i;
     214           5 :                         size_t j;
     215             : 
     216           5 :                         pos += strcpy_len(query + pos, " and tt.table_type_name in (", querylen - pos);
     217         258 :                         for (j = 0, i = 0; i < NameLength4 + 1; i++) {
     218         253 :                                 if (i == NameLength4 || TableType[i] == ',') {
     219          19 :                                         if (j > 0 && buf[j - 1] == ' ')
     220           1 :                                                 j--;
     221          19 :                                         if (j >= sizeof(buf) || j == 0) {
     222           0 :                                                 j = 0;
     223           0 :                                                 continue;
     224             :                                         }
     225          19 :                                         buf[j] = 0;
     226             :                                         /* Some ODBC applications use different table type names.
     227             :                                          * Replace some SQL synonyms to valid MonetDB
     228             :                                          * table type names as defined in sys.table_types */
     229          19 :                                         if (strcmp("BASE TABLE", buf) == 0) {
     230           2 :                                                 strcpy(buf, "TABLE");
     231             :                                         } else
     232          17 :                                         if (strcmp("GLOBAL TEMPORARY", buf) == 0) {
     233           2 :                                                 strcpy(buf, "GLOBAL TEMPORARY TABLE");
     234             :                                         } else
     235          15 :                                         if (strcmp("LOCAL TEMPORARY", buf) == 0) {
     236           2 :                                                 strcpy(buf, "LOCAL TEMPORARY TABLE");
     237             :                                         }
     238          19 :                                         pos += snprintf(query + pos, querylen - pos, "'%s',", buf);
     239          19 :                                         j = 0;
     240         234 :                                 } else if (j < sizeof(buf) &&
     241         224 :                                            TableType[i] != '\'' &&
     242          20 :                                            (TableType[i] != ' ' ||
     243          16 :                                             (j > 0 && buf[j - 1] != ' ')))
     244         220 :                                         buf[j++] = TableType[i];
     245             :                         }
     246           5 :                         if (query[pos - 1] == ',') {
     247           5 :                                 query[pos - 1] = ')';
     248             :                         } else {
     249             :                                 /* no extra tests added, so remove
     250             :                                  * clause completely */
     251           0 :                                 pos -= 28;
     252             :                         }
     253           5 :                         query[pos] = 0;
     254             :                 }
     255             : 
     256             :                 /* add the ordering */
     257           6 :                 pos += strcpy_len(query + pos, " order by \"TABLE_TYPE\", \"TABLE_SCHEM\", \"TABLE_NAME\"", querylen - pos);
     258           6 :                 assert(pos < querylen);
     259             :         }
     260             : 
     261             :         /* debug: fprintf(stdout, "SQLTables query (pos: %zu, len: %zu):\n%s\n\n", pos, strlen(query), query); */
     262             : 
     263             :         /* query the MonetDB data dictionary tables */
     264           9 :         rc = MNDBExecDirect(stmt, (SQLCHAR *) query, SQL_NTS);
     265             : 
     266           9 :         free(query);
     267             : 
     268           9 :         return rc;
     269             : 
     270           0 :   nomem:
     271           0 :         if (sch)
     272           0 :                 free(sch);
     273           0 :         if (tab)
     274           0 :                 free(tab);
     275             :         /* Memory allocation error */
     276           0 :         addStmtError(stmt, "HY001", NULL, 0);
     277           0 :         return SQL_ERROR;
     278             : }
     279             : 
     280             : SQLRETURN SQL_API
     281             : SQLTables(SQLHSTMT StatementHandle,
     282             :           SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
     283             :           SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
     284             :           SQLCHAR *TableName, SQLSMALLINT NameLength3,
     285             :           SQLCHAR *TableType, SQLSMALLINT NameLength4)
     286             : {
     287           9 :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     288             : 
     289             : #ifdef ODBCDEBUG
     290           9 :         ODBCLOG("SQLTables %p ", StatementHandle);
     291             : #endif
     292             : 
     293           9 :         if (!isValidStmt(stmt))
     294             :                  return SQL_INVALID_HANDLE;
     295             : 
     296           9 :         clearStmtErrors(stmt);
     297             : 
     298           9 :         return MNDBTables(stmt,
     299             :                           CatalogName, NameLength1,
     300             :                           SchemaName, NameLength2,
     301             :                           TableName, NameLength3,
     302             :                           TableType, NameLength4);
     303             : }
     304             : 
     305             : SQLRETURN SQL_API
     306             : SQLTablesA(SQLHSTMT StatementHandle,
     307             :            SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
     308             :            SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
     309             :            SQLCHAR *TableName, SQLSMALLINT NameLength3,
     310             :            SQLCHAR *TableType, SQLSMALLINT NameLength4)
     311             : {
     312           0 :         return SQLTables(StatementHandle,
     313             :                          CatalogName, NameLength1,
     314             :                          SchemaName, NameLength2,
     315             :                          TableName, NameLength3,
     316             :                          TableType, NameLength4);
     317             : }
     318             : 
     319             : SQLRETURN SQL_API
     320             : SQLTablesW(SQLHSTMT StatementHandle,
     321             :            SQLWCHAR *CatalogName, SQLSMALLINT NameLength1,
     322             :            SQLWCHAR *SchemaName, SQLSMALLINT NameLength2,
     323             :            SQLWCHAR *TableName, SQLSMALLINT NameLength3,
     324             :            SQLWCHAR *TableType, SQLSMALLINT NameLength4)
     325             : {
     326           0 :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     327           0 :         SQLRETURN rc = SQL_ERROR;
     328           0 :         SQLCHAR *catalog = NULL, *schema = NULL, *table = NULL, *type = NULL;
     329             : 
     330             : #ifdef ODBCDEBUG
     331           0 :         ODBCLOG("SQLTablesW %p ", StatementHandle);
     332             : #endif
     333             : 
     334           0 :         if (!isValidStmt(stmt))
     335             :                  return SQL_INVALID_HANDLE;
     336             : 
     337           0 :         clearStmtErrors(stmt);
     338             : 
     339           0 :         fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
     340             :                    addStmtError, stmt, goto bailout);
     341           0 :         fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
     342             :                    addStmtError, stmt, goto bailout);
     343           0 :         fixWcharIn(TableName, NameLength3, SQLCHAR, table,
     344             :                    addStmtError, stmt, goto bailout);
     345           0 :         fixWcharIn(TableType, NameLength4, SQLCHAR, type,
     346             :                    addStmtError, stmt, goto bailout);
     347             : 
     348           0 :         rc = MNDBTables(stmt,
     349             :                         catalog, SQL_NTS,
     350             :                         schema, SQL_NTS,
     351             :                         table, SQL_NTS,
     352             :                         type, SQL_NTS);
     353             : 
     354           0 :       bailout:
     355           0 :         if (catalog)
     356           0 :                 free(catalog);
     357           0 :         if (schema)
     358           0 :                 free(schema);
     359           0 :         if (table)
     360           0 :                 free(table);
     361           0 :         if (type)
     362           0 :                 free(type);
     363             : 
     364             :         return rc;
     365             : }

Generated by: LCOV version 1.14