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 (thats 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 9 : 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, stmt->Dbc->dbname) != 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 : }
|