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 : * SQLProcedures()
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 :
37 : static SQLRETURN
38 4 : MNDBProcedures(ODBCStmt *stmt,
39 : const SQLCHAR *CatalogName,
40 : SQLSMALLINT NameLength1,
41 : const SQLCHAR *SchemaName,
42 : SQLSMALLINT NameLength2,
43 : const SQLCHAR *ProcName,
44 : SQLSMALLINT NameLength3)
45 : {
46 4 : RETCODE rc;
47 :
48 : /* buffer for the constructed query to do meta data retrieval */
49 4 : char *query = NULL;
50 4 : size_t querylen;
51 4 : size_t pos = 0;
52 4 : char *sch = NULL, *pro = NULL;
53 :
54 : /* convert input string parameters to normal null terminated C strings */
55 4 : fixODBCstring(CatalogName, NameLength1, SQLSMALLINT,
56 : addStmtError, stmt, return SQL_ERROR);
57 4 : fixODBCstring(SchemaName, NameLength2, SQLSMALLINT,
58 : addStmtError, stmt, return SQL_ERROR);
59 4 : fixODBCstring(ProcName, NameLength3, SQLSMALLINT,
60 : addStmtError, stmt, return SQL_ERROR);
61 :
62 : #ifdef ODBCDEBUG
63 4 : ODBCLOG("\"%.*s\" \"%.*s\" \"%.*s\"\n",
64 : (int) NameLength1, CatalogName ? (char *) CatalogName : "",
65 : (int) NameLength2, SchemaName ? (char *) SchemaName : "",
66 : (int) NameLength3, ProcName ? (char *) ProcName : "");
67 : #endif
68 :
69 : /* SQLProcedures returns a table with the following columns:
70 : VARCHAR PROCEDURE_CAT
71 : VARCHAR PROCEDURE_SCHEM
72 : VARCHAR PROCEDURE_NAME NOT NULL
73 : N/A NUM_INPUT_PARAMS (Reserved for future use)
74 : N/A NUM_OUTPUT_PARAMS (Reserved for future use)
75 : N/A NUM_RESULT_SETS (Reserved for future use)
76 : VARCHAR REMARKS
77 : SMALLINT PROCEDURE_TYPE
78 : VARCHAR SPECIFIC_NAME (Note this is a MonetDB extension, needed to differentiate between overloaded procedure/function names)
79 : (similar to JDBC DatabaseMetaData methods getProcedures() and getFunctions())
80 : */
81 :
82 4 : if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
83 4 : if (NameLength2 > 0) {
84 4 : sch = ODBCParsePV("s", "name",
85 : (const char *) SchemaName,
86 : (size_t) NameLength2,
87 : stmt->Dbc);
88 4 : if (sch == NULL)
89 0 : goto nomem;
90 : }
91 4 : if (NameLength3 > 0) {
92 8 : pro = ODBCParsePV("p", "name",
93 : (const char *) ProcName,
94 : (size_t) NameLength3,
95 4 : stmt->Dbc);
96 4 : if (pro == NULL)
97 0 : goto nomem;
98 : }
99 : } else {
100 0 : if (NameLength2 > 0) {
101 0 : sch = ODBCParseID("s", "name",
102 : (const char *) SchemaName,
103 : (size_t) NameLength2);
104 0 : if (sch == NULL)
105 0 : goto nomem;
106 : }
107 0 : if (NameLength3 > 0) {
108 0 : pro = ODBCParseID("p", "name",
109 : (const char *) ProcName,
110 : (size_t) NameLength3);
111 0 : if (pro == NULL)
112 0 : goto nomem;
113 : }
114 : }
115 :
116 4 : querylen = 1000 + (sch ? strlen(sch) : 0) + (pro ? strlen(pro) : 0);
117 4 : query = malloc(querylen);
118 4 : if (query == NULL)
119 0 : goto nomem;
120 :
121 : /* see sql/include/sql_catalog.h */
122 : #define F_FUNC 1
123 : #define F_PROC 2
124 : #define F_UNION 5
125 4 : pos += snprintf(query + pos, querylen - pos,
126 : "select cast(null as varchar(1)) as \"PROCEDURE_CAT\", "
127 : "s.name as \"PROCEDURE_SCHEM\", "
128 : "p.name as \"PROCEDURE_NAME\", "
129 : "0 as \"NUM_INPUT_PARAMS\", "
130 : "0 as \"NUM_OUTPUT_PARAMS\", "
131 : "0 as \"NUM_RESULT_SETS\", "
132 : "%s as \"REMARKS\", "
133 : "cast(case when p.type = %d then %d else %d end as smallint) as \"PROCEDURE_TYPE\", "
134 : /* Only the id value uniquely identifies a specific procedure.
135 : Include it to be able to differentiate between multiple
136 : overloaded procedures with the same name and schema */
137 : "cast(p.id as varchar(10)) AS \"SPECIFIC_NAME\" "
138 : "from sys.schemas as s, "
139 : "sys.functions as p%s "
140 : "where p.schema_id = s.id and "
141 : "p.type in (%d, %d, %d)",
142 : stmt->Dbc->has_comment ? "c.remark" : "cast(null as varchar(1))",
143 : F_PROC, SQL_PT_PROCEDURE, SQL_PT_FUNCTION,
144 : /* from clause: */
145 4 : stmt->Dbc->has_comment ? " left outer join sys.comments c on c.id = p.id" : "",
146 : /* where clause: */
147 : F_FUNC, F_PROC, F_UNION);
148 4 : assert(pos < 900);
149 :
150 : /* Construct the selection condition query part */
151 4 : if (NameLength1 > 0 && CatalogName != NULL) {
152 : /* filtering requested on catalog name */
153 0 : if (strcmp((char *) CatalogName, stmt->Dbc->dbname) != 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 4 : if (sch) {
159 : /* filtering requested on schema name */
160 4 : pos += snprintf(query + pos, querylen - pos, " and %s", sch);
161 4 : free(sch);
162 : }
163 4 : if (pro) {
164 : /* filtering requested on procedure name */
165 4 : pos += snprintf(query + pos, querylen - pos, " and %s", pro);
166 4 : free(pro);
167 : }
168 :
169 : /* add the ordering (exclude procedure_cat as it is the same for all rows) */
170 4 : pos += strcpy_len(query + pos, " order by \"PROCEDURE_SCHEM\", \"PROCEDURE_NAME\", \"SPECIFIC_NAME\"", querylen - pos);
171 4 : assert(pos < querylen);
172 :
173 : /* debug: fprintf(stdout, "SQLProcedures query (pos: %zu, len: %zu):\n%s\n\n", pos, strlen(query), query); */
174 :
175 : /* query the MonetDB data dictionary tables */
176 4 : rc = MNDBExecDirect(stmt, (SQLCHAR *) query, (SQLINTEGER) pos);
177 :
178 4 : free(query);
179 :
180 4 : return rc;
181 :
182 0 : nomem:
183 : /* note that query must be NULL when we get here */
184 0 : if (sch)
185 0 : free(sch);
186 0 : if (pro)
187 0 : free(pro);
188 : /* Memory allocation error */
189 0 : addStmtError(stmt, "HY001", NULL, 0);
190 0 : return SQL_ERROR;
191 : }
192 :
193 : SQLRETURN SQL_API
194 : SQLProcedures(SQLHSTMT StatementHandle,
195 : SQLCHAR *CatalogName,
196 : SQLSMALLINT NameLength1,
197 : SQLCHAR *SchemaName,
198 : SQLSMALLINT NameLength2,
199 : SQLCHAR *ProcName,
200 : SQLSMALLINT NameLength3)
201 : {
202 4 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
203 :
204 : #ifdef ODBCDEBUG
205 4 : ODBCLOG("SQLProcedures %p ", StatementHandle);
206 : #endif
207 :
208 4 : if (!isValidStmt(stmt))
209 : return SQL_INVALID_HANDLE;
210 :
211 4 : clearStmtErrors(stmt);
212 :
213 4 : return MNDBProcedures(stmt,
214 : CatalogName, NameLength1,
215 : SchemaName, NameLength2,
216 : ProcName, NameLength3);
217 : }
218 :
219 : SQLRETURN SQL_API
220 : SQLProceduresA(SQLHSTMT StatementHandle,
221 : SQLCHAR *CatalogName,
222 : SQLSMALLINT NameLength1,
223 : SQLCHAR *SchemaName,
224 : SQLSMALLINT NameLength2,
225 : SQLCHAR *ProcName,
226 : SQLSMALLINT NameLength3)
227 : {
228 0 : return SQLProcedures(StatementHandle,
229 : CatalogName, NameLength1,
230 : SchemaName, NameLength2,
231 : ProcName, NameLength3);
232 : }
233 :
234 : SQLRETURN SQL_API
235 : SQLProceduresW(SQLHSTMT StatementHandle,
236 : SQLWCHAR *CatalogName, SQLSMALLINT NameLength1,
237 : SQLWCHAR *SchemaName, SQLSMALLINT NameLength2,
238 : SQLWCHAR *ProcName, SQLSMALLINT NameLength3)
239 : {
240 0 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
241 0 : SQLRETURN rc = SQL_ERROR;
242 0 : SQLCHAR *catalog = NULL, *schema = NULL, *proc = NULL;
243 :
244 : #ifdef ODBCDEBUG
245 0 : ODBCLOG("SQLProceduresW %p ", StatementHandle);
246 : #endif
247 :
248 0 : if (!isValidStmt(stmt))
249 : return SQL_INVALID_HANDLE;
250 :
251 0 : clearStmtErrors(stmt);
252 :
253 0 : fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
254 : addStmtError, stmt, goto bailout);
255 0 : fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
256 : addStmtError, stmt, goto bailout);
257 0 : fixWcharIn(ProcName, NameLength3, SQLCHAR, proc,
258 : addStmtError, stmt, goto bailout);
259 :
260 0 : rc = MNDBProcedures(stmt,
261 : catalog, SQL_NTS,
262 : schema, SQL_NTS,
263 : proc, SQL_NTS);
264 :
265 0 : bailout:
266 0 : if (catalog)
267 0 : free(catalog);
268 0 : if (schema)
269 0 : free(schema);
270 0 : if (proc)
271 0 : free(proc);
272 :
273 : return rc;
274 : }
|