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