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 : * SQLColumns()
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 : #include "ODBCQueries.h"
36 :
37 : #define NCOLUMNS 18
38 :
39 : static SQLRETURN
40 4 : MNDBColumns(ODBCStmt *stmt,
41 : const SQLCHAR *CatalogName,
42 : SQLSMALLINT NameLength1,
43 : const SQLCHAR *SchemaName,
44 : SQLSMALLINT NameLength2,
45 : const SQLCHAR *TableName,
46 : SQLSMALLINT NameLength3,
47 : const SQLCHAR *ColumnName,
48 : SQLSMALLINT NameLength4)
49 : {
50 4 : RETCODE rc;
51 :
52 : /* buffer for the constructed query to do meta data retrieval */
53 4 : char *query = NULL;
54 4 : size_t querylen;
55 4 : size_t pos = 0;
56 4 : char *sch = NULL, *tab = NULL, *col = NULL;
57 :
58 : /* null pointers not allowed if arguments are identifiers */
59 4 : if (stmt->Dbc->sql_attr_metadata_id == SQL_TRUE &&
60 0 : (SchemaName == NULL || TableName == NULL || ColumnName == NULL)) {
61 0 : addStmtError(stmt, "HY090", NULL, 0);
62 0 : return SQL_ERROR;
63 : }
64 :
65 4 : fixODBCstring(CatalogName, NameLength1, SQLSMALLINT,
66 : addStmtError, stmt, return SQL_ERROR);
67 4 : fixODBCstring(SchemaName, NameLength2, SQLSMALLINT,
68 : addStmtError, stmt, return SQL_ERROR);
69 4 : fixODBCstring(TableName, NameLength3, SQLSMALLINT,
70 : addStmtError, stmt, return SQL_ERROR);
71 4 : fixODBCstring(ColumnName, NameLength4, SQLSMALLINT,
72 : addStmtError, stmt, return SQL_ERROR);
73 :
74 : #ifdef ODBCDEBUG
75 4 : ODBCLOG(" \"%.*s\" \"%.*s\" \"%.*s\" \"%.*s\"\n",
76 : (int) NameLength1, CatalogName ? (char *) CatalogName : "",
77 : (int) NameLength2, SchemaName ? (char *) SchemaName : "",
78 : (int) NameLength3, TableName ? (char *) TableName : "",
79 : (int) NameLength4, ColumnName ? (char *) ColumnName : "");
80 : #endif
81 :
82 4 : if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
83 4 : if (NameLength2 > 0) {
84 3 : sch = ODBCParsePV("s", "name",
85 : (const char *) SchemaName,
86 : (size_t) NameLength2,
87 : stmt->Dbc);
88 3 : if (sch == NULL)
89 0 : goto nomem;
90 : }
91 4 : if (NameLength3 > 0) {
92 8 : tab = ODBCParsePV("t", "name",
93 : (const char *) TableName,
94 : (size_t) NameLength3,
95 4 : stmt->Dbc);
96 4 : if (tab == NULL)
97 0 : goto nomem;
98 : }
99 4 : if (NameLength4 > 0) {
100 6 : col = ODBCParsePV("c", "name",
101 : (const char *) ColumnName,
102 : (size_t) NameLength4,
103 3 : stmt->Dbc);
104 3 : if (col == NULL)
105 0 : goto nomem;
106 : }
107 : } else {
108 0 : if (NameLength2 > 0) {
109 0 : sch = ODBCParseID("s", "name",
110 : (const char *) SchemaName,
111 : (size_t) NameLength2);
112 0 : if (sch == NULL)
113 0 : goto nomem;
114 : }
115 0 : if (NameLength3 > 0) {
116 0 : tab = ODBCParseID("t", "name",
117 : (const char *) TableName,
118 : (size_t) NameLength3);
119 0 : if (tab == NULL)
120 0 : goto nomem;
121 : }
122 0 : if (NameLength4 > 0) {
123 0 : col = ODBCParseID("c", "name",
124 : (const char *) ColumnName,
125 : (size_t) NameLength4);
126 0 : if (col == NULL)
127 0 : goto nomem;
128 : }
129 : }
130 :
131 : /* construct the query now */
132 4 : querylen = 6600 + (sch ? strlen(sch) : 0) +
133 4 : (tab ? strlen(tab) : 0) + (col ? strlen(col) : 0);
134 4 : query = malloc(querylen);
135 4 : if (query == NULL)
136 0 : goto nomem;
137 :
138 : /* SQLColumns returns a table with the following columns:
139 : VARCHAR TABLE_CAT
140 : VARCHAR TABLE_SCHEM
141 : VARCHAR TABLE_NAME NOT NULL
142 : VARCHAR COLUMN_NAME NOT NULL
143 : SMALLINT DATA_TYPE NOT NULL
144 : VARCHAR TYPE_NAME NOT NULL
145 : INTEGER COLUMN_SIZE
146 : INTEGER BUFFER_LENGTH
147 : SMALLINT DECIMAL_DIGITS
148 : SMALLINT NUM_PREC_RADIX
149 : SMALLINT NULLABLE NOT NULL
150 : VARCHAR REMARKS
151 : VARCHAR COLUMN_DEF
152 : SMALLINT SQL_DATA_TYPE NOT NULL
153 : SMALLINT SQL_DATETIME_SUB
154 : INTEGER CHAR_OCTET_LENGTH
155 : INTEGER ORDINAL_POSITION NOT NULL
156 : VARCHAR IS_NULLABLE
157 : */
158 :
159 4 : pos += snprintf(query + pos, querylen - pos,
160 : "select cast(null as varchar(1)) as \"TABLE_CAT\", "
161 : "s.name as \"TABLE_SCHEM\", "
162 : "t.name as \"TABLE_NAME\", "
163 : "c.name as \"COLUMN_NAME\", "
164 : DATA_TYPE(c) ", "
165 : TYPE_NAME(c) ", "
166 : COLUMN_SIZE(c) ", "
167 : BUFFER_LENGTH(c) ", "
168 : DECIMAL_DIGITS(c) ", "
169 : NUM_PREC_RADIX(c) ", "
170 : "case c.\"null\" "
171 : "when true then cast(%d as smallint) "
172 : "when false then cast(%d as smallint) "
173 : "end as \"NULLABLE\", "
174 : "%s as \"REMARKS\", "
175 : "c.\"default\" as \"COLUMN_DEF\", "
176 : SQL_DATA_TYPE(c) ", "
177 : SQL_DATETIME_SUB(c) ", "
178 : CHAR_OCTET_LENGTH(c) ", "
179 : "cast(c.number + 1 as integer) as \"ORDINAL_POSITION\", "
180 : "case c.\"null\" "
181 : "when true then cast('YES' as varchar(3)) "
182 : "when false then cast('NO' as varchar(3)) "
183 : "end as \"IS_NULLABLE\" "
184 : "from sys.schemas s, "
185 : "sys.tables t, "
186 : "sys.columns c%s "
187 : "where s.id = t.schema_id and "
188 : "t.id = c.table_id",
189 : #ifdef DATA_TYPE_ARGS
190 : DATA_TYPE_ARGS,
191 : #endif
192 : #ifdef TYPE_NAME_ARGS
193 : TYPE_NAME_ARGS,
194 : #endif
195 : #ifdef COLUMN_SIZE_ARGS
196 : COLUMN_SIZE_ARGS,
197 : #endif
198 : #ifdef BUFFER_LENGTH_ARGS
199 : BUFFER_LENGTH_ARGS,
200 : #endif
201 : #ifdef DECIMAL_DIGITS_ARGS
202 : DECIMAL_DIGITS_ARGS,
203 : #endif
204 : #ifdef NUM_PREC_RADIX_ARGS
205 : NUM_PREC_RADIX_ARGS,
206 : #endif
207 : /* nullable: */
208 : SQL_NULLABLE, SQL_NO_NULLS,
209 : /* remarks: */
210 : stmt->Dbc->has_comment ? "com.remark" : "cast(null as varchar(1))",
211 : #ifdef SQL_DATA_TYPE_ARGS
212 : SQL_DATA_TYPE_ARGS,
213 : #endif
214 : #ifdef SQL_DATETIME_SUB_ARGS
215 : SQL_DATETIME_SUB_ARGS,
216 : #endif
217 : #ifdef CHAR_OCTET_LENGTH_ARGS
218 : CHAR_OCTET_LENGTH_ARGS,
219 : #endif
220 : /* from clause: */
221 4 : stmt->Dbc->has_comment ? " left outer join sys.comments com on com.id = c.id" : "");
222 :
223 : /* depending on the input parameter values we must add a
224 : variable selection condition dynamically */
225 :
226 : /* Construct the selection condition query part */
227 4 : if (NameLength1 > 0 && CatalogName != NULL) {
228 : /* filtering requested on catalog name */
229 0 : if (strcmp((char *) CatalogName, stmt->Dbc->dbname) != 0) {
230 : /* catalog name does not match the database name, so return no rows */
231 0 : pos += snprintf(query + pos, querylen - pos, " and 1=2");
232 : }
233 : }
234 4 : if (sch) {
235 : /* filtering requested on schema name */
236 3 : pos += snprintf(query + pos, querylen - pos, " and %s", sch);
237 3 : free(sch);
238 : }
239 4 : if (tab) {
240 : /* filtering requested on table name */
241 4 : pos += snprintf(query + pos, querylen - pos, " and %s", tab);
242 4 : free(tab);
243 : }
244 4 : if (col) {
245 : /* filtering requested on column name */
246 3 : pos += snprintf(query + pos, querylen - pos, " and %s", col);
247 3 : free(col);
248 : }
249 :
250 : /* add the ordering (exclude table_cat as it is the same for all rows) */
251 4 : pos += strcpy_len(query + pos, " order by \"TABLE_SCHEM\", \"TABLE_NAME\", \"ORDINAL_POSITION\"", querylen - pos);
252 4 : if (pos >= querylen)
253 0 : fprintf(stderr, "pos >= querylen, %zu > %zu\n", pos, querylen);
254 4 : assert(pos < querylen);
255 :
256 : /* debug: fprintf(stdout, "SQLColumns query (pos: %zu, len: %zu):\n%s\n\n", pos, strlen(query), query); */
257 :
258 : /* query the MonetDB data dictionary tables */
259 4 : rc = MNDBExecDirect(stmt, (SQLCHAR *) query, (SQLINTEGER) pos);
260 :
261 4 : free(query);
262 :
263 4 : return rc;
264 :
265 0 : nomem:
266 : /* note that query must be NULL when we get here */
267 0 : if (sch)
268 0 : free(sch);
269 0 : if (tab)
270 0 : free(tab);
271 0 : if (col)
272 0 : free(col);
273 : /* Memory allocation error */
274 0 : addStmtError(stmt, "HY001", NULL, 0);
275 0 : return SQL_ERROR;
276 : }
277 :
278 : SQLRETURN SQL_API
279 : SQLColumns(SQLHSTMT StatementHandle,
280 : SQLCHAR *CatalogName,
281 : SQLSMALLINT NameLength1,
282 : SQLCHAR *SchemaName,
283 : SQLSMALLINT NameLength2,
284 : SQLCHAR *TableName,
285 : SQLSMALLINT NameLength3,
286 : SQLCHAR *ColumnName,
287 : SQLSMALLINT NameLength4)
288 : {
289 4 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
290 :
291 : #ifdef ODBCDEBUG
292 4 : ODBCLOG("SQLColumns %p", StatementHandle);
293 : #endif
294 :
295 4 : if (!isValidStmt(stmt))
296 : return SQL_INVALID_HANDLE;
297 :
298 4 : clearStmtErrors(stmt);
299 :
300 4 : return MNDBColumns(stmt,
301 : CatalogName, NameLength1,
302 : SchemaName, NameLength2,
303 : TableName, NameLength3,
304 : ColumnName, NameLength4);
305 : }
306 :
307 : SQLRETURN SQL_API
308 : SQLColumnsA(SQLHSTMT StatementHandle,
309 : SQLCHAR *CatalogName,
310 : SQLSMALLINT NameLength1,
311 : SQLCHAR *SchemaName,
312 : SQLSMALLINT NameLength2,
313 : SQLCHAR *TableName,
314 : SQLSMALLINT NameLength3,
315 : SQLCHAR *ColumnName,
316 : SQLSMALLINT NameLength4)
317 : {
318 0 : return SQLColumns(StatementHandle,
319 : CatalogName, NameLength1,
320 : SchemaName, NameLength2,
321 : TableName, NameLength3,
322 : ColumnName, NameLength4);
323 : }
324 :
325 : SQLRETURN SQL_API
326 : SQLColumnsW(SQLHSTMT StatementHandle,
327 : SQLWCHAR *CatalogName,
328 : SQLSMALLINT NameLength1,
329 : SQLWCHAR *SchemaName,
330 : SQLSMALLINT NameLength2,
331 : SQLWCHAR *TableName,
332 : SQLSMALLINT NameLength3,
333 : SQLWCHAR *ColumnName,
334 : SQLSMALLINT NameLength4)
335 : {
336 0 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
337 0 : SQLCHAR *catalog = NULL, *schema = NULL, *table = NULL, *column = NULL;
338 0 : SQLRETURN rc = SQL_ERROR;
339 :
340 : #ifdef ODBCDEBUG
341 0 : ODBCLOG("SQLColumnsW %p", StatementHandle);
342 : #endif
343 :
344 0 : if (!isValidStmt(stmt))
345 : return SQL_INVALID_HANDLE;
346 :
347 0 : clearStmtErrors(stmt);
348 :
349 0 : fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
350 : addStmtError, stmt, goto bailout);
351 0 : fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
352 : addStmtError, stmt, goto bailout);
353 0 : fixWcharIn(TableName, NameLength3, SQLCHAR, table,
354 : addStmtError, stmt, goto bailout);
355 0 : fixWcharIn(ColumnName, NameLength4, SQLCHAR, column,
356 : addStmtError, stmt, goto bailout);
357 :
358 0 : rc = MNDBColumns(stmt,
359 : catalog, SQL_NTS,
360 : schema, SQL_NTS,
361 : table, SQL_NTS,
362 : column, SQL_NTS);
363 :
364 0 : bailout:
365 0 : if (catalog)
366 0 : free(catalog);
367 0 : if (schema)
368 0 : free(schema);
369 0 : if (table)
370 0 : free(table);
371 0 : if (column)
372 0 : free(column);
373 : return rc;
374 : }
|