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 : * SQLTablePrivileges()
25 : * CLI Compliance: ODBC (Microsoft)
26 : *
27 : * Note: this function is not implemented (it only sets an error),
28 : * because MonetDB SQL frontend does not support table based authorization.
29 : *
30 : * Author: Martin van Dinther, Sjoerd Mullender
31 : * Date : 30 aug 2002
32 : *
33 : **********************************************************************/
34 :
35 : #include "ODBCGlobal.h"
36 : #include "ODBCStmt.h"
37 : #include "ODBCUtil.h"
38 :
39 :
40 : static SQLRETURN
41 8 : MNDBTablePrivileges(ODBCStmt *stmt,
42 : const SQLCHAR *CatalogName,
43 : SQLSMALLINT NameLength1,
44 : const SQLCHAR *SchemaName,
45 : SQLSMALLINT NameLength2,
46 : const SQLCHAR *TableName,
47 : SQLSMALLINT NameLength3)
48 : {
49 8 : RETCODE rc;
50 8 : char *query = NULL;
51 8 : size_t querylen;
52 8 : size_t pos = 0;
53 8 : char *sch = NULL, *tab = NULL;
54 :
55 8 : fixODBCstring(CatalogName, NameLength1, SQLSMALLINT,
56 : addStmtError, stmt, return SQL_ERROR);
57 8 : fixODBCstring(SchemaName, NameLength2, SQLSMALLINT,
58 : addStmtError, stmt, return SQL_ERROR);
59 8 : fixODBCstring(TableName, NameLength3, SQLSMALLINT,
60 : addStmtError, stmt, return SQL_ERROR);
61 :
62 : #ifdef ODBCDEBUG
63 8 : ODBCLOG("\"%.*s\" \"%.*s\" \"%.*s\"\n",
64 : (int) NameLength1, CatalogName ? (char *) CatalogName : "",
65 : (int) NameLength2, SchemaName ? (char *) SchemaName : "",
66 : (int) NameLength3, TableName ? (char *) TableName : "");
67 : #endif
68 :
69 8 : if (stmt->Dbc->sql_attr_metadata_id == SQL_FALSE) {
70 8 : if (NameLength2 > 0) {
71 8 : sch = ODBCParsePV("s", "name",
72 : (const char *) SchemaName,
73 : (size_t) NameLength2,
74 : stmt->Dbc);
75 8 : if (sch == NULL)
76 0 : goto nomem;
77 : }
78 8 : if (NameLength3 > 0) {
79 16 : tab = ODBCParsePV("t", "name",
80 : (const char *) TableName,
81 : (size_t) NameLength3,
82 8 : stmt->Dbc);
83 8 : if (tab == NULL)
84 0 : goto nomem;
85 : }
86 : } else {
87 0 : if (NameLength2 > 0) {
88 0 : sch = ODBCParseID("s", "name",
89 : (const char *) SchemaName,
90 : (size_t) NameLength2);
91 0 : if (sch == NULL)
92 0 : goto nomem;
93 : }
94 0 : if (NameLength3 > 0) {
95 0 : tab = ODBCParseID("t", "name",
96 : (const char *) TableName,
97 : (size_t) NameLength3);
98 0 : if (tab == NULL)
99 0 : goto nomem;
100 : }
101 : }
102 :
103 : /* construct the query now */
104 8 : querylen = 1000 + (sch ? strlen(sch) : 0) + (tab ? strlen(tab) : 0);
105 8 : query = malloc(querylen);
106 8 : if (query == NULL)
107 0 : goto nomem;
108 :
109 : /* SQLTablePrivileges returns a table with the following columns:
110 : TABLE_CAT VARCHAR
111 : TABLE_SCHEM VARCHAR
112 : TABLE_NAME VARCHAR NOT NULL
113 : GRANTOR VARCHAR
114 : GRANTEE VARCHAR NOT NULL
115 : PRIVILEGE VARCHAR NOT NULL
116 : IS_GRANTABLE VARCHAR
117 : */
118 :
119 16 : pos += snprintf(query + pos, querylen - pos,
120 : "select cast(null as varchar(1)) as \"TABLE_CAT\", "
121 : "s.name as \"TABLE_SCHEM\", "
122 : "t.name as \"TABLE_NAME\", "
123 : "case a.id "
124 : "when s.owner then '_SYSTEM' "
125 : "else g.name "
126 : "end as \"GRANTOR\", "
127 : "case a.name "
128 : "when 'public' then 'PUBLIC' "
129 : "else a.name "
130 : "end as \"GRANTEE\", "
131 : "pc.privilege_code_name as \"PRIVILEGE\", "
132 : "case p.grantable "
133 : "when 1 then 'YES' "
134 : "when 0 then 'NO' "
135 : "end as \"IS_GRANTABLE\" "
136 : "from sys.schemas s, "
137 : /* next union all subquery is much more efficient than using sys.tables */
138 : "(select t1.id, t1.name, t1.schema_id from sys._tables as t1"
139 : " where not t1.system" /* exclude system tables and views */
140 : " union all"
141 : " select t2.id, t2.name, t2.schema_id from tmp._tables as t2)"
142 : " as t(id, name, schema_id), "
143 : "sys.auths a, "
144 : "sys.privileges p, "
145 : "sys.auths g, "
146 : "%s "
147 : "where p.obj_id = t.id and "
148 : "p.auth_id = a.id and "
149 : "t.schema_id = s.id and "
150 : "p.grantor = g.id and "
151 : "p.privileges = pc.privilege_code_id",
152 : /* a server that supports sys.comments also supports
153 : * sys.privilege_codes */
154 8 : stmt->Dbc->has_comment ? "sys.privilege_codes as pc" :
155 : "(values (1, 'SELECT'), "
156 : "(2, 'UPDATE'), "
157 : "(4, 'INSERT'), "
158 : "(8, 'DELETE'), "
159 : "(16, 'EXECUTE'), "
160 : "(32, 'GRANT')) as pc(privilege_code_id, privilege_code_name)");
161 8 : assert(pos < 900);
162 :
163 : /* Construct the selection condition query part */
164 8 : if (NameLength1 > 0 && CatalogName != NULL) {
165 : /* filtering requested on catalog name */
166 0 : if (strcmp((char *) CatalogName, stmt->Dbc->dbname) != 0) {
167 : /* catalog name does not match the database name, so return no rows */
168 0 : pos += snprintf(query + pos, querylen - pos, " and 1=2");
169 : }
170 : }
171 8 : if (sch) {
172 : /* filtering requested on schema name */
173 8 : pos += snprintf(query + pos, querylen - pos, " and %s", sch);
174 8 : free(sch);
175 : }
176 8 : if (tab) {
177 : /* filtering requested on table name */
178 8 : pos += snprintf(query + pos, querylen - pos, " and %s", tab);
179 8 : free(tab);
180 : }
181 :
182 : /* add the ordering (exclude table_cat as it is the same for all rows) */
183 8 : pos += strcpy_len(query + pos, " order by \"TABLE_SCHEM\", \"TABLE_NAME\", \"PRIVILEGE\", \"GRANTEE\"", querylen - pos);
184 8 : assert(pos < querylen);
185 :
186 : /* debug: fprintf(stdout, "SQLTablePrivileges query (pos: %zu, len: %zu):\n%s\n\n", pos, strlen(query), query); */
187 :
188 : /* query the MonetDB data dictionary tables */
189 8 : rc = MNDBExecDirect(stmt, (SQLCHAR *) query, (SQLINTEGER) pos);
190 :
191 8 : free(query);
192 :
193 8 : return rc;
194 :
195 0 : nomem:
196 : /* note that query must be NULL when we get here */
197 0 : if (sch)
198 0 : free(sch);
199 0 : if (tab)
200 0 : free(tab);
201 : /* Memory allocation error */
202 0 : addStmtError(stmt, "HY001", NULL, 0);
203 0 : return SQL_ERROR;
204 : }
205 :
206 : SQLRETURN SQL_API
207 : SQLTablePrivileges(SQLHSTMT StatementHandle,
208 : SQLCHAR *CatalogName,
209 : SQLSMALLINT NameLength1,
210 : SQLCHAR *SchemaName,
211 : SQLSMALLINT NameLength2,
212 : SQLCHAR *TableName,
213 : SQLSMALLINT NameLength3)
214 : {
215 8 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
216 :
217 : #ifdef ODBCDEBUG
218 8 : ODBCLOG("SQLTablePrivileges %p ", StatementHandle);
219 : #endif
220 :
221 8 : if (!isValidStmt(stmt))
222 : return SQL_INVALID_HANDLE;
223 :
224 8 : clearStmtErrors(stmt);
225 :
226 8 : return MNDBTablePrivileges(stmt,
227 : CatalogName, NameLength1,
228 : SchemaName, NameLength2,
229 : TableName, NameLength3);
230 : }
231 :
232 : SQLRETURN SQL_API
233 : SQLTablePrivilegesA(SQLHSTMT StatementHandle,
234 : SQLCHAR *CatalogName,
235 : SQLSMALLINT NameLength1,
236 : SQLCHAR *SchemaName,
237 : SQLSMALLINT NameLength2,
238 : SQLCHAR *TableName,
239 : SQLSMALLINT NameLength3)
240 : {
241 0 : return SQLTablePrivileges(StatementHandle,
242 : CatalogName, NameLength1,
243 : SchemaName, NameLength2,
244 : TableName, NameLength3);
245 : }
246 :
247 : SQLRETURN SQL_API
248 : SQLTablePrivilegesW(SQLHSTMT StatementHandle,
249 : SQLWCHAR *CatalogName,
250 : SQLSMALLINT NameLength1,
251 : SQLWCHAR *SchemaName,
252 : SQLSMALLINT NameLength2,
253 : SQLWCHAR *TableName,
254 : SQLSMALLINT NameLength3)
255 : {
256 0 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
257 0 : SQLRETURN rc = SQL_ERROR;
258 0 : SQLCHAR *catalog = NULL, *schema = NULL, *table = NULL;
259 :
260 : #ifdef ODBCDEBUG
261 0 : ODBCLOG("SQLTablePrivilegesW %p ", StatementHandle);
262 : #endif
263 :
264 0 : if (!isValidStmt(stmt))
265 : return SQL_INVALID_HANDLE;
266 :
267 0 : clearStmtErrors(stmt);
268 :
269 0 : fixWcharIn(CatalogName, NameLength1, SQLCHAR, catalog,
270 : addStmtError, stmt, goto bailout);
271 0 : fixWcharIn(SchemaName, NameLength2, SQLCHAR, schema,
272 : addStmtError, stmt, goto bailout);
273 0 : fixWcharIn(TableName, NameLength3, SQLCHAR, table,
274 : addStmtError, stmt, goto bailout);
275 :
276 0 : rc = MNDBTablePrivileges(stmt,
277 : catalog, SQL_NTS,
278 : schema, SQL_NTS,
279 : table, SQL_NTS);
280 :
281 0 : bailout:
282 0 : if (catalog)
283 0 : free(catalog);
284 0 : if (schema)
285 0 : free(schema);
286 0 : if (table)
287 0 : free(table);
288 :
289 : return rc;
290 : }
|