LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLPrimaryKeys.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 58 102 56.9 %
Date: 2024-10-07 21:21:43 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             :  * SQLPrimaryKeys()
      25             :  * CLI Compliance: ODBC (Microsoft)
      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 : MNDBPrimaryKeys(ODBCStmt *stmt,
      38             :                 const SQLCHAR *CatalogName,
      39             :                 SQLSMALLINT NameLength1,
      40             :                 const SQLCHAR *SchemaName,
      41             :                 SQLSMALLINT NameLength2,
      42             :                 const SQLCHAR *TableName,
      43             :                 SQLSMALLINT NameLength3)
      44             : {
      45           9 :         RETCODE rc;
      46             : 
      47             :         /* buffer for the constructed query to do meta data retrieval */
      48           9 :         char *query = NULL;
      49           9 :         size_t querylen;
      50           9 :         size_t pos = 0;
      51           9 :         char *sch = NULL, *tab = NULL;
      52           9 :         bool addTmpQuery = false;
      53             : 
      54             :         /* deal with SQL_NTS and SQL_NULL_DATA */
      55           9 :         fixODBCstring(CatalogName, NameLength1, SQLSMALLINT,
      56             :                       addStmtError, stmt, return SQL_ERROR);
      57           9 :         fixODBCstring(SchemaName, NameLength2, SQLSMALLINT,
      58             :                       addStmtError, stmt, return SQL_ERROR);
      59           9 :         fixODBCstring(TableName, NameLength3, SQLSMALLINT,
      60             :                       addStmtError, stmt, return SQL_ERROR);
      61             : 
      62             :         /* check if a valid (non null, not empty) table name is supplied */
      63           9 :         if (TableName == NULL) {
      64             :                 /* Invalid use of null pointer */
      65           0 :                 addStmtError(stmt, "HY009", NULL, 0);
      66           0 :                 return SQL_ERROR;
      67             :         }
      68           9 :         if (NameLength3 == 0) {
      69             :                 /* Invalid string or buffer length */
      70           0 :                 addStmtError(stmt, "HY090", NULL, 0);
      71           0 :                 return SQL_ERROR;
      72             :         }
      73             : 
      74             : #ifdef ODBCDEBUG
      75          12 :         ODBCLOG("\"%.*s\" \"%.*s\" \"%.*s\"\n",
      76             :                 (int) NameLength1, CatalogName ? (char *) CatalogName : "",
      77             :                 (int) NameLength2, SchemaName ? (char *) SchemaName : "",
      78             :                 (int) NameLength3, (char *) TableName);
      79             : #endif
      80             : 
      81           9 :         if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
      82           9 :                 if (NameLength2 > 0) {
      83           8 :                         sch = ODBCParseOA("s", "name",
      84             :                                           (const char *) SchemaName,
      85             :                                           (size_t) NameLength2);
      86           8 :                         if (sch == NULL)
      87           0 :                                 goto nomem;
      88             :                 }
      89           9 :                 if (NameLength3 > 0) {
      90           9 :                         tab = ODBCParseOA("t", "name",
      91             :                                           (const char *) TableName,
      92             :                                           (size_t) NameLength3);
      93           9 :                         if (tab == NULL)
      94           0 :                                 goto nomem;
      95             :                 }
      96             :         } else {
      97           0 :                 if (NameLength2 > 0) {
      98           0 :                         sch = ODBCParseID("s", "name",
      99             :                                           (const char *) SchemaName,
     100             :                                           (size_t) NameLength2);
     101           0 :                         if (sch == NULL)
     102           0 :                                 goto nomem;
     103             :                 }
     104           0 :                 if (NameLength3 > 0) {
     105           0 :                         tab = ODBCParseID("t", "name",
     106             :                                           (const char *) TableName,
     107             :                                           (size_t) NameLength3);
     108           0 :                         if (tab == NULL)
     109           0 :                                 goto nomem;
     110             :                 }
     111             :         }
     112             : 
     113             :         /* determine if we need to add a query against the tmp.* tables */
     114          18 :         addTmpQuery = (SchemaName == NULL)
     115           9 :                    || (SchemaName != NULL
     116           8 :                         && (strcmp((const char *) SchemaName, "tmp") == 0
     117           4 :                          || strchr((const char *) SchemaName, '%') != NULL
     118           4 :                          || strchr((const char *) SchemaName, '_') != NULL));
     119             : 
     120             :         /* construct the query */
     121           9 :         querylen = 1000 + (sch ? strlen(sch) : 0) + (tab ? strlen(tab) : 0);
     122           9 :         if (addTmpQuery)
     123           5 :                 querylen *= 2;
     124           9 :         query = malloc(querylen);
     125           9 :         if (query == NULL)
     126           0 :                 goto nomem;
     127             : 
     128             :         /* SQLPrimaryKeys returns a table with the following columns:
     129             :            VARCHAR      TABLE_CAT
     130             :            VARCHAR      TABLE_SCHEM
     131             :            VARCHAR      TABLE_NAME NOT NULL
     132             :            VARCHAR      COLUMN_NAME NOT NULL
     133             :            SMALLINT     KEY_SEQ NOT NULL
     134             :            VARCHAR      PK_NAME
     135             :         */
     136           9 :         pos += snprintf(query + pos, querylen - pos,
     137             :                 "select cast(null as varchar(1)) as \"TABLE_CAT\", "
     138             :                         "s.name as \"TABLE_SCHEM\", "
     139             :                         "t.name as \"TABLE_NAME\", "
     140             :                         "kc.name as \"COLUMN_NAME\", "
     141             :                         "cast(kc.nr + 1 as smallint) as \"KEY_SEQ\", "
     142             :                         "k.name as \"PK_NAME\" "
     143             :                 "from sys.keys k, sys.objects kc, sys._tables t, sys.schemas s "
     144             :                 "where k.type = 0 and "
     145             :                      "k.id = kc.id and "
     146             :                      "k.table_id = t.id and "
     147             :                      "t.schema_id = s.id");
     148           9 :         assert(pos < 800);
     149             : 
     150             :         /* Construct the selection condition query part */
     151           9 :         if (NameLength1 > 0 && CatalogName != NULL) {
     152             :                 /* filtering requested on catalog name */
     153           0 :                 if (strcmp((char *) CatalogName, msetting_string(stmt->Dbc->settings, MP_DATABASE)) != 0) {
     154             :                         /* catalog name does not match the database name, so return no rows */
     155           0 :                         pos += snprintf(query + pos, querylen - pos, " and 1=2");
     156             :                 }
     157             :         }
     158           9 :         if (sch) {
     159             :                 /* filtering requested on schema name */
     160           8 :                 pos += snprintf(query + pos, querylen - pos, " and %s", sch);
     161             :         }
     162           9 :         if (tab) {
     163             :                 /* filtering requested on table name */
     164           9 :                 pos += snprintf(query + pos, querylen - pos, " and %s", tab);
     165             :         }
     166             : 
     167           9 :         if (addTmpQuery) {
     168             :                 /* we must also include the keys of local temporary tables
     169             :                    which are stored in tmp.keys, tmp.objects and tmp._tables */
     170           5 :                 pos += snprintf(query + pos, querylen - pos,
     171             :                         " UNION ALL "
     172             :                         "select cast(null as varchar(1)) as \"TABLE_CAT\", "
     173             :                                 "s.name as \"TABLE_SCHEM\", "
     174             :                                 "t.name as \"TABLE_NAME\", "
     175             :                                 "kc.name as \"COLUMN_NAME\", "
     176             :                                 "cast(kc.nr + 1 as smallint) as \"KEY_SEQ\", "
     177             :                                 "k.name as \"PK_NAME\" "
     178             :                         "from tmp.keys k, tmp.objects kc, tmp._tables t, sys.schemas s "
     179             :                         "where k.type = 0 and "
     180             :                              "k.id = kc.id and "
     181             :                              "k.table_id = t.id and "
     182             :                              "t.schema_id = s.id");
     183             : 
     184             :                 /* Construct the selection condition query part */
     185           5 :                 if (NameLength1 > 0 && CatalogName != NULL) {
     186             :                         /* filtering requested on catalog name */
     187           0 :                         if (strcmp((char *) CatalogName, msetting_string(stmt->Dbc->settings, MP_DATABASE)) != 0) {
     188             :                                 /* catalog name does not match the database name, so return no rows */
     189           0 :                                 pos += snprintf(query + pos, querylen - pos, " and 1=2");
     190             :                         }
     191             :                 }
     192           5 :                 if (sch) {
     193             :                         /* filtering requested on schema name */
     194           4 :                         pos += snprintf(query + pos, querylen - pos, " and %s", sch);
     195             :                 }
     196           5 :                 if (tab) {
     197             :                         /* filtering requested on table name */
     198           5 :                         pos += snprintf(query + pos, querylen - pos, " and %s", tab);
     199             :                 }
     200             :         }
     201             : 
     202           9 :         if (sch)
     203           8 :                 free(sch);
     204           9 :         if (tab)
     205           9 :                 free(tab);
     206             : 
     207             :         /* add the ordering */
     208           9 :         pos += strcpy_len(query + pos, " order by \"TABLE_SCHEM\", \"TABLE_NAME\", \"KEY_SEQ\"", querylen - pos);
     209           9 :         assert(pos < querylen);
     210             : 
     211             :         /* debug: fprintf(stdout, "SQLPrimaryKeys query (pos: %zu, len: %zu):\n%s\n\n", pos, strlen(query), query); */
     212             : 
     213             :         /* query the MonetDB data dictionary tables */
     214           9 :         rc = MNDBExecDirect(stmt, (SQLCHAR *) query, (SQLINTEGER) pos);
     215             : 
     216           9 :         free(query);
     217             : 
     218           9 :         return rc;
     219             : 
     220           0 :   nomem:
     221             :         /* note that query must be NULL when we get here */
     222           0 :         if (sch)
     223           0 :                 free(sch);
     224           0 :         if (tab)
     225           0 :                 free(tab);
     226             :         /* Memory allocation error */
     227           0 :         addStmtError(stmt, "HY001", NULL, 0);
     228           0 :         return SQL_ERROR;
     229             : }
     230             : 
     231             : SQLRETURN SQL_API
     232             : SQLPrimaryKeys(SQLHSTMT StatementHandle,
     233             :                SQLCHAR *CatalogName,
     234             :                SQLSMALLINT NameLength1,
     235             :                SQLCHAR *SchemaName,
     236             :                SQLSMALLINT NameLength2,
     237             :                SQLCHAR *TableName,
     238             :                SQLSMALLINT NameLength3)
     239             : {
     240           9 :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     241             : 
     242             : #ifdef ODBCDEBUG
     243           9 :         ODBCLOG("SQLPrimaryKeys %p ", StatementHandle);
     244             : #endif
     245             : 
     246           9 :         if (!isValidStmt(stmt))
     247             :                  return SQL_INVALID_HANDLE;
     248             : 
     249           9 :         clearStmtErrors(stmt);
     250             : 
     251           9 :         return MNDBPrimaryKeys(stmt,
     252             :                                CatalogName, NameLength1,
     253             :                                SchemaName, NameLength2,
     254             :                                TableName, NameLength3);
     255             : }
     256             : 
     257             : SQLRETURN SQL_API
     258             : SQLPrimaryKeysA(SQLHSTMT StatementHandle,
     259             :                 SQLCHAR *CatalogName,
     260             :                 SQLSMALLINT NameLength1,
     261             :                 SQLCHAR *SchemaName,
     262             :                 SQLSMALLINT NameLength2,
     263             :                 SQLCHAR *TableName,
     264             :                 SQLSMALLINT NameLength3)
     265             : {
     266           0 :         return SQLPrimaryKeys(StatementHandle,
     267             :                               CatalogName, NameLength1,
     268             :                               SchemaName, NameLength2,
     269             :                               TableName, NameLength3);
     270             : }
     271             : 
     272             : SQLRETURN SQL_API
     273             : SQLPrimaryKeysW(SQLHSTMT StatementHandle,
     274             :                 SQLWCHAR *CatalogName,
     275             :                 SQLSMALLINT NameLength1,
     276             :                 SQLWCHAR *SchemaName,
     277             :                 SQLSMALLINT NameLength2,
     278             :                 SQLWCHAR *TableName,
     279             :                 SQLSMALLINT NameLength3)
     280             : {
     281           0 :         ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
     282           0 :         SQLRETURN rc = SQL_ERROR;
     283           0 :         SQLCHAR *catalog = NULL, *schema = NULL, *table = NULL;
     284             : 
     285             : #ifdef ODBCDEBUG
     286           0 :         ODBCLOG("SQLPrimaryKeysW %p ", StatementHandle);
     287             : #endif
     288             : 
     289           0 :         if (!isValidStmt(stmt))
     290             :                  return SQL_INVALID_HANDLE;
     291             : 
     292           0 :         clearStmtErrors(stmt);
     293             : 
     294           0 :         fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
     295             :                    addStmtError, stmt, goto bailout);
     296           0 :         fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
     297             :                    addStmtError, stmt, goto bailout);
     298           0 :         fixWcharIn(TableName, NameLength3, SQLCHAR, table,
     299             :                    addStmtError, stmt, goto bailout);
     300             : 
     301           0 :         rc = MNDBPrimaryKeys(stmt,
     302             :                              catalog, SQL_NTS,
     303             :                              schema, SQL_NTS,
     304             :                              table, SQL_NTS);
     305             : 
     306           0 :       bailout:
     307           0 :         if (catalog)
     308           0 :                 free(catalog);
     309           0 :         if (schema)
     310           0 :                 free(schema);
     311           0 :         if (table)
     312           0 :                 free(table);
     313             : 
     314             :         return rc;
     315             : }

Generated by: LCOV version 1.14