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 : /* multi version catalog */
14 :
15 : #include "monetdb_config.h"
16 : #include "gdk.h"
17 :
18 : #include "sql_mvc.h"
19 : #include "sql_qc.h"
20 : #include "sql_types.h"
21 : #include "sql_env.h"
22 : #include "sql_semantic.h"
23 : #include "sql_partition.h"
24 : #include "sql_privileges.h"
25 : #include "mapi_querytype.h"
26 : #include "rel_rel.h"
27 : #include "rel_exp.h"
28 : #include "rel_semantic.h"
29 : #include "rel_unnest.h"
30 : #include "rel_optimizer.h"
31 : #include "rel_statistics.h"
32 :
33 : #include "mal_authorize.h"
34 : #include "mal_profiler.h"
35 : #include "mal_exception.h"
36 : #include "mal_interpreter.h"
37 :
38 : static void
39 223 : sql_create_comments(mvc *m, sql_schema *s)
40 : {
41 223 : sql_table *t = NULL;
42 223 : sql_column *c = NULL;
43 223 : sql_key *k = NULL;
44 :
45 223 : mvc_create_table(&t, m, s, "comments", tt_table, 1, SQL_PERSIST, 0, -1, 0);
46 223 : mvc_create_column_(&c, m, t, "id", "int", 32);
47 223 : sql_trans_create_ukey(&k, m->session->tr, t, "comments_id_pkey", pkey);
48 223 : sql_trans_create_kc(m->session->tr, k, c);
49 223 : sql_trans_key_done(m->session->tr, k);
50 223 : sql_trans_create_dependency(m->session->tr, c->base.id, k->idx->base.id, INDEX_DEPENDENCY);
51 223 : mvc_create_column_(&c, m, t, "remark", "varchar", 65000);
52 223 : sql_trans_alter_null(m->session->tr, c, 0);
53 223 : }
54 :
55 : static sql_table *
56 446 : mvc_init_create_view(mvc *m, sql_schema *s, const char *name, const char *query)
57 : {
58 446 : sql_table *t = NULL;
59 :
60 446 : mvc_create_view(&t, m, s, name, SQL_PERSIST, query, 1);
61 446 : if (t) {
62 446 : char *buf;
63 446 : sql_rel *r = NULL;
64 :
65 446 : if (!(buf = sa_strdup(m->ta, t->query))) {
66 0 : (void) sql_error(m, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
67 0 : return NULL;
68 : }
69 :
70 446 : r = rel_parse(m, s, buf, m_deps);
71 446 : if (r)
72 446 : r = sql_processrelation(m, r, 0, 0, 0, 0);
73 446 : if (r) {
74 446 : list *blist = rel_dependencies(m, r);
75 446 : if (mvc_create_dependencies(m, blist, t->base.id, VIEW_DEPENDENCY)) {
76 0 : sa_reset(m->ta);
77 0 : (void) sql_error(m, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
78 0 : return NULL;
79 : }
80 : }
81 446 : sa_reset(m->ta);
82 446 : assert(r);
83 : }
84 446 : return t;
85 : }
86 :
87 : #define MVC_INIT_DROP_TABLE(SQLID, TNAME, VIEW, NCOL) \
88 : do { \
89 : str output; \
90 : t = mvc_bind_table(m, s, TNAME); \
91 : SQLID = t->base.id; \
92 : for (int i = 0; i < NCOL; i++) { \
93 : sql_column *col = mvc_bind_column(m, t, VIEW[i].name); \
94 : VIEW[i].oldid = col->base.id; \
95 : } \
96 : if ((output = mvc_drop_table(m, s, t, 0)) != MAL_SUCCEED) { \
97 : mvc_destroy(m); \
98 : mvc_exit(store); \
99 : TRC_CRITICAL(SQL_TRANS, \
100 : "Initialization error: %s\n", output); \
101 : freeException(output); \
102 : return NULL; \
103 : } \
104 : } while (0)
105 :
106 : struct view_t {
107 : const char *name;
108 : const char *type;
109 : unsigned int digits;
110 : sqlid oldid;
111 : sqlid newid;
112 : };
113 :
114 : static void
115 0 : mvc_fix_depend(mvc *m, sql_column *depids, struct view_t *v, int n)
116 : {
117 0 : sqlstore *store = m->store;
118 0 : oid rid;
119 0 : rids *rs;
120 :
121 0 : for (int i = 0; i < n; i++) {
122 0 : rs = store->table_api.rids_select(m->session->tr, depids,
123 0 : &v[i].oldid, &v[i].oldid, NULL);
124 0 : if (rs) {
125 0 : while ((rid = store->table_api.rids_next(rs)), !is_oid_nil(rid)) {
126 0 : store->table_api.column_update_value(m->session->tr, depids, rid, &v[i].newid);
127 : }
128 0 : store->table_api.rids_destroy(rs);
129 : }
130 : }
131 0 : }
132 :
133 : sql_store
134 336 : mvc_init(int debug, store_type store_tpe, int ro, int su, const char *initpasswd)
135 : {
136 336 : sqlstore *store = NULL;
137 336 : sql_schema *s;
138 336 : sql_table *t;
139 336 : mvc *m;
140 336 : str msg;
141 :
142 336 : TRC_DEBUG(SQL_TRANS, "Initialization\n");
143 336 : keyword_init();
144 336 : if (scanner_init_keywords() != 0) {
145 0 : TRC_CRITICAL(SQL_TRANS, "Malloc failure\n");
146 0 : return NULL;
147 : }
148 :
149 336 : if ((store = store_init(debug, store_tpe, ro, su)) == NULL) {
150 1 : keyword_exit();
151 1 : TRC_CRITICAL(SQL_TRANS, "Unable to create system tables\n");
152 1 : return NULL;
153 : }
154 :
155 335 : initialize_sql_functions_lookup(store->sa);
156 :
157 335 : m = mvc_create((sql_store)store, store->sa, 0, 0, NULL, NULL);
158 335 : if (!m) {
159 0 : mvc_exit(store);
160 0 : TRC_CRITICAL(SQL_TRANS, "Malloc failure\n");
161 0 : return NULL;
162 : }
163 :
164 335 : assert(m->sa == NULL);
165 335 : m->sa = sa_create(m->pa);
166 335 : if (!m->sa) {
167 0 : mvc_destroy(m);
168 0 : mvc_exit(store);
169 0 : TRC_CRITICAL(SQL_TRANS, "Malloc failure\n");
170 0 : return NULL;
171 : }
172 :
173 335 : if (store->first || store->catalog_version) {
174 223 : sqlid tid = 0, cid = 0;
175 223 : struct view_t tview[10] = {
176 : {
177 : .name = "id",
178 : .type = "int",
179 : .digits = 32,
180 : },
181 : {
182 : .name = "name",
183 : .type = "varchar",
184 : .digits = 1024,
185 : },
186 : {
187 : .name = "schema_id",
188 : .type = "int",
189 : .digits = 32,
190 : },
191 : {
192 : .name = "query",
193 : .type = "varchar",
194 : .digits = 1 << 20,
195 : },
196 : {
197 : .name = "type",
198 : .type = "smallint",
199 : .digits = 16,
200 : },
201 : {
202 : .name = "system",
203 : .type = "boolean",
204 : .digits = 1,
205 : },
206 : {
207 : .name = "commit_action",
208 : .type = "smallint",
209 : .digits = 16,
210 : },
211 : {
212 : .name = "access",
213 : .type = "smallint",
214 : .digits = 16,
215 : },
216 : {
217 : .name = "temporary",
218 : .type = "smallint",
219 : .digits = 16,
220 : },
221 : {
222 : 0
223 : },
224 223 : }, cview[11] = {
225 : {
226 : .name = "id",
227 : .type = "int",
228 : .digits = 32,
229 : },
230 : {
231 : .name = "name",
232 : .type = "varchar",
233 : .digits = 1024,
234 : },
235 : {
236 : .name = "type",
237 : .type = "varchar",
238 : .digits = 1024,
239 : },
240 : {
241 : .name = "type_digits",
242 : .type = "int",
243 : .digits = 32,
244 : },
245 : {
246 : .name = "type_scale",
247 : .type = "int",
248 : .digits = 32,
249 : },
250 : {
251 : .name = "table_id",
252 : .type = "int",
253 : .digits = 32,
254 : },
255 : {
256 : .name = "default",
257 : .type = "varchar",
258 : .digits = STORAGE_MAX_VALUE_LENGTH,
259 : },
260 : {
261 : .name = "null",
262 : .type = "boolean",
263 : .digits = 1,
264 : },
265 : {
266 : .name = "number",
267 : .type = "int",
268 : .digits = 32,
269 : },
270 : {
271 : .name = "storage",
272 : .type = "varchar",
273 : .digits = 2048,
274 : },
275 : {
276 : 0
277 : },
278 : };
279 223 : if (mvc_trans(m) < 0) {
280 0 : mvc_destroy(m);
281 0 : mvc_exit(store);
282 0 : TRC_CRITICAL(SQL_TRANS, "Failed to start transaction\n");
283 0 : return NULL;
284 : }
285 223 : s = m->session->schema = mvc_bind_schema(m, "sys");
286 223 : assert(m->session->schema != NULL);
287 :
288 223 : if (!store->first) {
289 0 : MVC_INIT_DROP_TABLE(tid, "tables", tview, 9);
290 0 : MVC_INIT_DROP_TABLE(cid, "columns", cview, 10);
291 : }
292 :
293 223 : t = mvc_init_create_view(m, s, "tables", "SELECT \"id\", \"name\", \"schema_id\", \"query\", CAST(CASE WHEN \"system\" THEN \"type\" + 10 /* system table/view */ ELSE (CASE WHEN \"commit_action\" = 0 THEN \"type\" /* table/view */ ELSE \"type\" + 20 /* global temp table */ END) END AS SMALLINT) AS \"type\", \"system\", \"commit_action\", \"access\", CASE WHEN (NOT \"system\" AND \"commit_action\" > 0) THEN 1 ELSE 0 END AS \"temporary\" FROM \"sys\".\"_tables\" WHERE \"type\" <> 2 UNION ALL SELECT \"id\", \"name\", \"schema_id\", \"query\", CAST(\"type\" + 30 /* local temp table */ AS SMALLINT) AS \"type\", \"system\", \"commit_action\", \"access\", 1 AS \"temporary\" FROM \"tmp\".\"_tables\";");
294 223 : if (!t) {
295 0 : mvc_destroy(m);
296 0 : mvc_exit(store);
297 0 : TRC_CRITICAL(SQL_TRANS, "Failed to create 'tables' view\n");
298 0 : return NULL;
299 : }
300 :
301 2230 : for (int i = 0; i < 9; i++) {
302 2007 : sql_column *col = NULL;
303 :
304 2007 : mvc_create_column_(&col, m, t, tview[i].name, tview[i].type, tview[i].digits);
305 2007 : if (col == NULL) {
306 0 : mvc_destroy(m);
307 0 : mvc_exit(store);
308 0 : TRC_CRITICAL(SQL_TRANS,
309 : "Initialization: creation of sys.tables column %s failed\n", tview[i].name);
310 0 : return NULL;
311 : }
312 2007 : tview[i].newid = col->base.id;
313 : }
314 :
315 223 : if (!store->first) {
316 0 : int pub = ROLE_PUBLIC;
317 0 : int p = PRIV_SELECT;
318 0 : int zero = 0;
319 0 : sql_table *privs = find_sql_table(m->session->tr, s, "privileges");
320 0 : sql_table *deps = find_sql_table(m->session->tr, s, "dependencies");
321 0 : store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
322 0 : assert(tview[9].name == NULL);
323 0 : tview[9].oldid = tid;
324 0 : tview[9].newid = t->base.id;
325 0 : mvc_fix_depend(m, find_sql_column(deps, "id"), tview, 10);
326 0 : mvc_fix_depend(m, find_sql_column(deps, "depend_id"), tview, 10);
327 : }
328 :
329 223 : t = mvc_init_create_view(m, s, "columns", "SELECT * FROM (SELECT p.* FROM \"sys\".\"_columns\" AS p UNION ALL SELECT t.* FROM \"tmp\".\"_columns\" AS t) AS columns;");
330 223 : if (!t) {
331 0 : mvc_destroy(m);
332 0 : mvc_exit(store);
333 0 : TRC_CRITICAL(SQL_TRANS, "Failed to create 'columns' view\n");
334 0 : return NULL;
335 : }
336 2453 : for (int i = 0; i < 10; i++) {
337 2230 : sql_column *col = NULL;
338 :
339 2230 : mvc_create_column_(&col, m, t, cview[i].name, cview[i].type, cview[i].digits);
340 2230 : if (col == NULL) {
341 0 : mvc_destroy(m);
342 0 : mvc_exit(store);
343 0 : TRC_CRITICAL(SQL_TRANS,
344 : "Initialization: creation of sys.tables column %s failed\n", cview[i].name);
345 0 : return NULL;
346 : }
347 2230 : cview[i].newid = col->base.id;
348 : }
349 :
350 223 : if (!store->first) {
351 0 : int pub = ROLE_PUBLIC;
352 0 : int p = PRIV_SELECT;
353 0 : int zero = 0;
354 0 : sql_table *privs = find_sql_table(m->session->tr, s, "privileges");
355 0 : sql_table *deps = find_sql_table(m->session->tr, s, "dependencies");
356 0 : store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
357 0 : assert(cview[10].name == NULL);
358 0 : cview[10].oldid = cid;
359 0 : cview[10].newid = t->base.id;
360 0 : mvc_fix_depend(m, find_sql_column(deps, "id"), cview, 11);
361 0 : mvc_fix_depend(m, find_sql_column(deps, "depend_id"), cview, 11);
362 : } else {
363 223 : sql_create_env(m, s);
364 223 : sql_create_comments(m, s);
365 223 : sql_create_privileges(m, s, initpasswd);
366 : }
367 :
368 223 : if ((msg = mvc_commit(m, 0, NULL, false)) != MAL_SUCCEED) {
369 0 : TRC_CRITICAL(SQL_TRANS, "Unable to commit system tables: %s\n", (msg + 6));
370 0 : freeException(msg);
371 0 : mvc_destroy(m);
372 0 : mvc_exit(store);
373 0 : return NULL;
374 : }
375 : }
376 :
377 335 : if (mvc_trans(m) < 0) {
378 0 : mvc_destroy(m);
379 0 : mvc_exit(store);
380 0 : TRC_CRITICAL(SQL_TRANS, "Failed to start transaction\n");
381 0 : return NULL;
382 : }
383 :
384 : //as the sql_parser is not yet initialized in the storage, we determine the sql type of the sql_parts here
385 :
386 335 : struct os_iter si;
387 335 : os_iterator(&si, m->session->tr->cat->schemas, m->session->tr, NULL);
388 1813 : for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
389 1478 : sql_schema *ss = (sql_schema*)b;
390 1478 : struct os_iter oi;
391 1478 : os_iterator(&oi, ss->tables, m->session->tr, NULL);
392 24164 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
393 22686 : sql_table *tt = (sql_table*)b;
394 22686 : if (isPartitionedByColumnTable(tt) || isPartitionedByExpressionTable(tt)) {
395 45 : char *err;
396 45 : if ((err = parse_sql_parts(m, tt)) != NULL) {
397 0 : TRC_CRITICAL(SQL_TRANS, "Unable to start partitioned table: %s.%s: %s\n", ss->base.name, tt->base.name, err);
398 0 : freeException(err);
399 0 : mvc_destroy(m);
400 0 : mvc_exit(store);
401 0 : return NULL;
402 : }
403 : }
404 : }
405 : }
406 335 : if (sql_trans_convert_partitions(m->session->tr) < 0) {
407 0 : TRC_CRITICAL(SQL_TRANS, "Unable to start partitioned tables\n");
408 0 : mvc_destroy(m);
409 0 : mvc_exit(store);
410 0 : return NULL;
411 : }
412 :
413 335 : if ((msg = mvc_commit(m, 0, NULL, false)) != MAL_SUCCEED) {
414 0 : TRC_CRITICAL(SQL_TRANS, "Unable to commit system tables: %s\n", (msg + 6));
415 0 : freeException(msg);
416 0 : mvc_destroy(m);
417 0 : mvc_exit(store);
418 0 : return NULL;
419 : }
420 335 : mvc_destroy(m);
421 335 : return store;
422 : }
423 :
424 : void
425 334 : mvc_exit(sql_store store)
426 : {
427 334 : TRC_DEBUG(SQL_TRANS, "MVC exit\n");
428 334 : store_exit(store);
429 334 : keyword_exit();
430 334 : }
431 :
432 : void
433 334 : mvc_logmanager(sql_store store)
434 : {
435 334 : store_manager(store);
436 333 : }
437 :
438 : int
439 1430883 : mvc_status(mvc *m)
440 : {
441 1430883 : int res = m->session->status;
442 :
443 1430883 : return res;
444 : }
445 :
446 : int
447 0 : mvc_error_retry(mvc *m)
448 : {
449 0 : int res = m->session->status;
450 :
451 0 : if (!res || res == -ERR_AMBIGUOUS || res == -ERR_GROUPBY)
452 0 : return 0;
453 : return res;
454 : }
455 :
456 : int
457 0 : mvc_type(mvc *m)
458 : {
459 0 : int res = m->type;
460 :
461 0 : m->type = Q_PARSE;
462 0 : return res;
463 : }
464 :
465 : int
466 51488 : mvc_debug_on(mvc *m, int flg)
467 : {
468 :
469 51488 : if (m->debug & flg)
470 0 : return 1;
471 :
472 : return 0;
473 : }
474 :
475 : void
476 0 : mvc_cancel_session(mvc *m)
477 : {
478 0 : (void)sql_trans_end(m->session, SQL_ERR);
479 0 : }
480 :
481 : int
482 216515 : mvc_trans(mvc *m)
483 : {
484 216515 : int res = 0, err = m->session->status;
485 216515 : assert(!m->session->tr->active); /* can only start a new transaction */
486 :
487 216515 : TRC_INFO(SQL_TRANS, "Starting transaction\n");
488 216515 : res = sql_trans_begin(m->session);
489 216517 : if (m->qc && (res || err))
490 20491 : qc_restart(m->qc);
491 216517 : return res;
492 : }
493 :
494 : str
495 154285 : mvc_commit(mvc *m, int chain, const char *name, bool enabling_auto_commit)
496 : {
497 154285 : sql_trans *tr = m->session->tr;
498 154285 : int ok = SQL_OK;
499 154285 : str msg = MAL_SUCCEED, other;
500 154285 : char operation[BUFSIZ];
501 :
502 154285 : assert(tr);
503 154285 : assert(m->session->tr->active); /* only commit an active transaction */
504 154285 : TRC_DEBUG(SQL_TRANS,"Commit: %s\n", (name) ? name : "");
505 154285 : if(enabling_auto_commit)
506 0 : snprintf(operation, BUFSIZ, "Commit failed while enabling auto_commit: ");
507 154285 : else if(name)
508 45 : snprintf(operation, BUFSIZ, "SAVEPOINT: (%s)", name);
509 : else
510 154240 : snprintf(operation, BUFSIZ, "COMMIT:");
511 :
512 154285 : if (m->session->status < 0) {
513 12 : msg = createException(SQL, "sql.commit", SQLSTATE(40000) "%s transaction is aborted, will ROLLBACK instead", operation);
514 12 : if ((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
515 0 : freeException(other);
516 12 : return msg;
517 : }
518 :
519 : /* savepoint, simply make a new sub transaction */
520 154273 : if (name && name[0] != '\0') {
521 45 : sql_trans *tr = m->session->tr;
522 45 : TRC_DEBUG(SQL_TRANS, "Savepoint\n");
523 45 : if (!(m->session->tr = sql_trans_create(m->store, tr, name)))
524 0 : return createException(SQL, "sql.commit", SQLSTATE(HY013) "%s allocation failure while creating savepoint", operation);
525 :
526 45 : if (!(m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name))) {
527 0 : m->session->tr = sql_trans_destroy(m->session->tr);
528 0 : return createException(SQL, "sql.commit", SQLSTATE(40000) "%s finished successfully, but the session's schema could not be found on the current transaction", operation);
529 : }
530 45 : m->type = Q_TRANS;
531 45 : TRC_INFO(SQL_TRANS, "Savepoint commit '%s' done\n", name);
532 45 : return msg;
533 : }
534 :
535 154228 : if (!tr->parent && !name) {
536 154221 : lng Tbegin = 0;
537 154221 : ulng ts_start = 0;
538 154221 : bool log_usec = profilerMode == 0 || m->session->auto_commit;
539 154221 : if(profilerStatus > 0) {
540 0 : if (log_usec) Tbegin = GDKusec();
541 0 : ts_start = m->session->tr->ts;
542 : }
543 :
544 154221 : const int state = sql_trans_end(m->session, ok);
545 :
546 154223 : if(profilerStatus > 0) {
547 0 : lng Tend = GDKusec();
548 0 : Client c = mal_clients+m->clientid;
549 0 : profilerEvent(NULL,
550 : &(struct NonMalEvent)
551 0 : { state == SQL_CONFLICT ? CONFLICT : COMMIT , c, Tend, &ts_start, &m->session->tr->ts, state == SQL_ERR, log_usec?Tend-Tbegin:0});
552 : }
553 154223 : switch (state) {
554 0 : case SQL_ERR:
555 0 : GDKfatal("%s transaction commit failed; exiting (kernel error: %s)", operation, GDKerrbuf);
556 908 : break;
557 908 : case SQL_CONFLICT:
558 :
559 : /* transaction conflict */
560 908 : return createException(SQL, "sql.commit", SQLSTATE(40001) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
561 : default:
562 153315 : break;
563 : }
564 153315 : if (chain) {
565 2 : if (sql_trans_begin(m->session) < 0)
566 0 : return createException(SQL, "sql.commit", SQLSTATE(40000) "%s finished successfully, but the session's schema could not be found while starting the next transaction", operation);
567 2 : m->session->auto_commit = 0; /* disable auto-commit while chaining */
568 : }
569 153315 : m->type = Q_TRANS;
570 153315 : TRC_INFO(SQL_TRANS,
571 : "Commit done\n");
572 153315 : return msg;
573 : }
574 :
575 : /* save points only */
576 : assert(name || tr->parent);
577 :
578 : /* commit and cleanup nested transactions */
579 7 : if (tr->parent) {
580 14 : while (tr->parent != NULL && ok == SQL_OK) {
581 9 : if ((ok = sql_trans_commit(tr)) == SQL_ERR)
582 0 : GDKfatal("%s transaction commit failed; exiting (kernel error: %s)", operation, GDKerrbuf);
583 7 : m->session->tr = tr = sql_trans_destroy(tr);
584 : }
585 5 : while (tr->parent != NULL)
586 0 : m->session->tr = tr = sql_trans_destroy(tr);
587 5 : if (ok != SQL_OK)
588 0 : msg = createException(SQL, "sql.commit", SQLSTATE(40001) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
589 : }
590 :
591 : /* if there is nothing to commit reuse the current transaction */
592 5 : if (list_empty(tr->changes)) {
593 0 : if (!chain) {
594 0 : switch (sql_trans_end(m->session, ok)) {
595 0 : case SQL_ERR:
596 0 : GDKfatal("%s transaction commit failed; exiting (kernel error: %s)", operation, GDKerrbuf);
597 0 : break;
598 0 : case SQL_CONFLICT:
599 0 : if (!msg)
600 0 : msg = createException(SQL, "sql.commit", SQLSTATE(40001) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
601 : break;
602 : default:
603 : break;
604 : }
605 : }
606 0 : m->type = Q_TRANS;
607 0 : TRC_INFO(SQL_TRANS,
608 : "Commit done (no changes)\n");
609 0 : return msg;
610 : }
611 :
612 5 : switch (sql_trans_end(m->session, ok)) {
613 0 : case SQL_ERR:
614 0 : GDKfatal("%s transaction commit failed; exiting (kernel error: %s)", operation, GDKerrbuf);
615 0 : break;
616 0 : case SQL_CONFLICT:
617 0 : if (!msg)
618 0 : msg = createException(SQL, "sql.commit", SQLSTATE(40001) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
619 : return msg;
620 : default:
621 5 : break;
622 : }
623 5 : if (chain) {
624 0 : if (sql_trans_begin(m->session) < 0) {
625 0 : if (!msg)
626 0 : msg = createException(SQL, "sql.commit", SQLSTATE(40000) "%s finished successfully, but the session's schema could not be found while starting the next transaction", operation);
627 0 : return msg;
628 : }
629 0 : m->session->auto_commit = 0; /* disable auto-commit while chaining */
630 : }
631 5 : m->type = Q_TRANS;
632 5 : TRC_INFO(SQL_TRANS,
633 : "Commit done\n");
634 : return msg;
635 : }
636 :
637 : str
638 62136 : mvc_rollback(mvc *m, int chain, const char *name, bool disabling_auto_commit)
639 : {
640 62136 : str msg = MAL_SUCCEED;
641 :
642 62136 : TRC_DEBUG(SQL_TRANS, "Rollback: %s\n", (name) ? name : "");
643 62136 : (void) disabling_auto_commit;
644 :
645 62136 : sql_trans *tr = m->session->tr;
646 62136 : assert(m->session->tr && m->session->tr->active); /* only abort an active transaction */
647 62136 : if (name && name[0] != '\0') {
648 38 : while (tr && (!tr->name || strcmp(tr->name, name) != 0))
649 20 : tr = tr->parent;
650 18 : if (!tr || !tr->name || strcmp(tr->name, name) != 0) {
651 2 : msg = createException(SQL, "sql.rollback", SQLSTATE(42000) "ROLLBACK TO SAVEPOINT: no such savepoint: '%s'", name);
652 2 : m->session->status = -1;
653 2 : return msg;
654 : }
655 : tr = m->session->tr;
656 34 : while (!tr->name || strcmp(tr->name, name) != 0) {
657 : /* make sure we do not reuse changed data */
658 18 : if (!list_empty(tr->changes))
659 9 : tr->status = 1;
660 18 : m->session->tr = tr = sql_trans_destroy(tr);
661 : }
662 : /* start a new transaction after rolling back */
663 16 : if (!(m->session->tr = tr = sql_trans_create(m->store, tr, name))) {
664 0 : msg = createException(SQL, "sql.rollback", SQLSTATE(HY013) "ROLLBACK TO SAVEPOINT: allocation failure while restarting savepoint");
665 0 : m->session->status = -1;
666 0 : return msg;
667 : }
668 16 : m->session->status = tr->parent->status;
669 16 : if (!(m->session->schema = find_sql_schema(tr, m->session->schema_name))) {
670 1 : msg = createException(SQL, "sql.rollback", SQLSTATE(40000) "ROLLBACK TO SAVEPOINT: finished successfully, but the session's schema could not be found on the current transaction");
671 1 : m->session->status = -1;
672 1 : return msg;
673 : }
674 : } else {
675 : /* first release all intermediate savepoints */
676 62133 : while (tr->parent != NULL)
677 15 : m->session-> tr = tr = sql_trans_destroy(tr);
678 : /* make sure we do not reuse changed data */
679 62118 : if (!list_empty(tr->changes))
680 1113 : tr->status = 1;
681 :
682 :
683 62118 : lng Tbegin = 0;
684 62118 : ulng ts_start = 0;
685 62118 : bool log_usec = profilerMode == 0 || m->session->auto_commit;
686 62118 : if(profilerStatus > 0) {
687 0 : if (log_usec) Tbegin = GDKusec();
688 0 : ts_start = m->session->tr->ts;
689 : }
690 62118 : (void) sql_trans_end(m->session, SQL_ERR);
691 :
692 62118 : if(profilerStatus > 0) {
693 0 : lng Tend = GDKusec();
694 0 : Client c = mal_clients+m->clientid;
695 0 : profilerEvent(NULL,
696 : &(struct NonMalEvent)
697 0 : { ROLLBACK , c, Tend, &ts_start, &m->session->tr->ts, 0, log_usec?Tend-Tbegin:0});
698 : }
699 62118 : if (chain) {
700 2 : if (sql_trans_begin(m->session) < 0) {
701 1 : msg = createException(SQL, "sql.rollback", SQLSTATE(40000) "ROLLBACK: finished successfully, but the session's schema could not be found while starting the next transaction");
702 1 : m->session->status = -1;
703 1 : return msg;
704 : }
705 1 : m->session->auto_commit = 0; /* disable auto-commit while chaining */
706 : }
707 : }
708 62132 : if (msg != MAL_SUCCEED) {
709 : m->session->status = -1;
710 : return msg;
711 : }
712 62132 : m->type = Q_TRANS;
713 62132 : TRC_INFO(SQL_TRANS,
714 : "Commit%s%s rolled back%s\n",
715 : name ? " " : "", name ? name : "",
716 : list_empty(tr->changes) ? " (no changes)" : "");
717 : return msg;
718 : }
719 :
720 : /* release all savepoints up including the given named savepoint
721 : * but keep the current changes.
722 : * */
723 : str
724 12 : mvc_release(mvc *m, const char *name)
725 : {
726 12 : sql_trans *tr = m->session->tr;
727 12 : str msg = MAL_SUCCEED;
728 :
729 12 : assert(tr && tr->active); /* only release active transactions */
730 :
731 12 : TRC_DEBUG(SQL_TRANS, "Release: %s\n", (name) ? name : "");
732 :
733 12 : if (!name && (msg = mvc_rollback(m, 0, name, false)) != MAL_SUCCEED) {
734 0 : m->session->status = -1;
735 0 : return msg;
736 : }
737 :
738 33 : while (tr && (!tr->name || strcmp(tr->name, name) != 0))
739 21 : tr = tr->parent;
740 12 : if (!tr || !tr->name || strcmp(tr->name, name) != 0) {
741 0 : msg = createException(SQL, "sql.release", SQLSTATE(42000) "RELEASE: no such savepoint: '%s'", name);
742 0 : m->session->status = -1;
743 0 : return msg;
744 : }
745 12 : tr = m->session->tr;
746 33 : while (!tr->name || strcmp(tr->name, name) != 0) {
747 : /* commit all intermediate savepoints */
748 21 : if (sql_trans_commit(tr) != SQL_OK)
749 0 : GDKfatal("release savepoints should not fail");
750 21 : m->session->tr = tr = sql_trans_destroy(tr);
751 : }
752 12 : _DELETE(m->session->tr->name); /* name will no longer be used */
753 12 : m->session->status = tr->status;
754 12 : if (!(m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name))) {
755 0 : msg = createException(SQL, "sql.release", SQLSTATE(40000) "RELEASE: finished successfully, but the session's schema could not be found on the current transaction");
756 0 : m->session->status = -1;
757 0 : return msg;
758 : }
759 :
760 12 : m->type = Q_TRANS;
761 12 : return msg;
762 : }
763 :
764 : static void
765 76473 : _free(void *dummy, void *data)
766 : {
767 76473 : (void)dummy;
768 76473 : GDKfree(data);
769 76473 : }
770 :
771 : mvc *
772 38588 : mvc_create(sql_store *store, sql_allocator *pa, int clientid, int debug, bstream *rs, stream *ws)
773 : {
774 38588 : mvc *m;
775 38588 : str sys_str = NULL;
776 :
777 38588 : assert(pa);
778 38588 : m = SA_ZNEW(pa, mvc);
779 38588 : if (!m)
780 : return NULL;
781 :
782 38588 : TRC_DEBUG(SQL_TRANS, "MVC create\n");
783 :
784 38588 : m->errstr[0] = '\0';
785 : /* if an error exceeds the buffer we don't want garbage at the end */
786 38588 : m->errstr[ERRSIZE-1] = '\0';
787 :
788 38588 : m->qc = qc_create(pa, clientid, 0);
789 38588 : if (!m->qc) {
790 : return NULL;
791 : }
792 38588 : m->pa = pa;
793 38588 : m->sa = NULL;
794 38588 : m->ta = sa_create(m->pa);
795 : #if defined(__GNUC__) || defined(__clang__)
796 38588 : m->sp = (uintptr_t) __builtin_frame_address(0);
797 : #else
798 : m->sp = (uintptr_t)(&m);
799 : #endif
800 :
801 38588 : m->params = NULL;
802 38588 : m->sizeframes = MAXPARAMS;
803 38588 : m->frames = SA_NEW_ARRAY(pa, sql_frame*, m->sizeframes);
804 38588 : m->topframes = 0;
805 38588 : m->frame = 0;
806 :
807 38588 : m->use_views = false;
808 38588 : if (!m->frames) {
809 0 : qc_destroy(m->qc);
810 0 : return NULL;
811 : }
812 38588 : if (init_global_variables(m) < 0) {
813 0 : qc_destroy(m->qc);
814 0 : list_destroy(m->global_vars);
815 0 : return NULL;
816 : }
817 38588 : m->sym = NULL;
818 :
819 38588 : m->role_id = m->user_id = -1;
820 38588 : m->timezone = 0;
821 38588 : m->sql_optimizer = INT_MAX;
822 38588 : m->clientid = clientid;
823 :
824 38588 : m->emode = m_normal;
825 38588 : m->emod = mod_none;
826 38588 : m->reply_size = 100;
827 38588 : m->debug = debug;
828 :
829 38588 : m->label = 0;
830 38588 : m->cascade_action = NULL;
831 38588 : m->runs = NULL;
832 :
833 38588 : if (!(m->schema_path = list_create((fdestroy)_free))) {
834 0 : qc_destroy(m->qc);
835 0 : list_destroy(m->global_vars);
836 0 : return NULL;
837 : }
838 38588 : if (!(sys_str = _STRDUP("sys")) || !list_append(m->schema_path, sys_str)) {
839 0 : _DELETE(sys_str);
840 0 : qc_destroy(m->qc);
841 0 : list_destroy(m->global_vars);
842 0 : list_destroy(m->schema_path);
843 0 : return NULL;
844 : }
845 38588 : m->schema_path_has_sys = true;
846 38588 : m->schema_path_has_tmp = false;
847 38588 : m->store = store;
848 :
849 38588 : m->session = sql_session_create(m->store, m->pa, 1 /*autocommit on*/);
850 38588 : if (!m->session) {
851 0 : qc_destroy(m->qc);
852 0 : list_destroy(m->global_vars);
853 0 : list_destroy(m->schema_path);
854 0 : return NULL;
855 : }
856 :
857 38588 : m->type = Q_PARSE;
858 :
859 38588 : scanner_init(&m->scanner, rs, ws);
860 38588 : return m;
861 : }
862 :
863 : void
864 38588 : mvc_destroy(mvc *m)
865 : {
866 38588 : sql_trans *tr;
867 :
868 38588 : TRC_DEBUG(SQL_TRANS, "MVC destroy\n");
869 38588 : tr = m->session->tr;
870 38588 : if (tr) {
871 38588 : if (m->session->tr->active)
872 0 : (void)sql_trans_end(m->session, SQL_ERR);
873 38588 : while (tr->parent)
874 0 : m->session->tr = tr = sql_trans_destroy(tr);
875 : }
876 38588 : sql_session_destroy(m->session);
877 :
878 38588 : list_destroy(m->global_vars);
879 38588 : list_destroy(m->schema_path);
880 38588 : stack_pop_until(m, 0);
881 :
882 38588 : if (m->scanner.log) /* close and destroy stream */
883 0 : close_stream(m->scanner.log);
884 :
885 38588 : m->sa = NULL;
886 38588 : m->ta = NULL;
887 38588 : if (m->qc)
888 38588 : qc_destroy(m->qc);
889 38588 : m->qc = NULL;
890 38588 : }
891 :
892 : sql_type *
893 37367 : mvc_bind_type(mvc *sql, const char *name)
894 : {
895 37367 : sql_type *t = sql_trans_bind_type(sql->session->tr, NULL, name);
896 37367 : TRC_DEBUG(SQL_TRANS, "Bind type: %s\n", name);
897 37367 : return t;
898 : }
899 :
900 : sql_type *
901 1810 : schema_bind_type(mvc *sql, sql_schema *s, const char *name)
902 : {
903 1810 : sql_type *t = find_sql_type(sql->session->tr, s, name);
904 :
905 1810 : (void) sql;
906 1810 : if (!t)
907 : return NULL;
908 8 : TRC_DEBUG(SQL_TRANS, "Schema bind type: %s\n", name);
909 : return t;
910 : }
911 :
912 : sql_schema *
913 7794008 : mvc_bind_schema(mvc *m, const char *sname)
914 : {
915 7794008 : sql_trans *tr = m->session->tr;
916 7794008 : sql_schema *s;
917 :
918 7794008 : if (!tr)
919 : return NULL;
920 :
921 7794008 : s = find_sql_schema(tr, sname);
922 7792892 : if (!s)
923 : return NULL;
924 7726135 : TRC_DEBUG(SQL_TRANS, "Bind schema: %s\n", sname);
925 : return s;
926 : }
927 :
928 : sql_table *
929 4202298 : mvc_bind_table(mvc *m, sql_schema *s, const char *tname)
930 : {
931 4202298 : sql_table *t = find_sql_table(m->session->tr, s, tname);
932 :
933 4202046 : (void) m;
934 4202046 : if (!t)
935 : return NULL;
936 :
937 3928380 : TRC_DEBUG(SQL_TRANS, "Bind table: %s.%s\n", s->base.name, tname);
938 : return t;
939 : }
940 :
941 : sql_column *
942 3024125 : mvc_bind_column(mvc *m, sql_table *t, const char *cname)
943 : {
944 3024125 : sql_column *c;
945 :
946 3024125 : (void)m;
947 3024125 : c = find_sql_column(t, cname);
948 3024097 : if (!c)
949 : return NULL;
950 2822816 : TRC_DEBUG(SQL_TRANS, "Bind column: %s.%s\n", t->base.name, cname);
951 : return c;
952 : }
953 :
954 : static sql_column *
955 0 : first_column(sql_table *t)
956 : {
957 0 : node *n = ol_first_node(t->columns);
958 :
959 0 : if (n)
960 0 : return n->data;
961 : return NULL;
962 : }
963 :
964 : sql_column *
965 0 : mvc_first_column(mvc *m, sql_table *t)
966 : {
967 0 : sql_column *c = first_column(t);
968 :
969 0 : (void) m;
970 0 : if (!c)
971 : return NULL;
972 0 : TRC_DEBUG(SQL_TRANS, "First column: %s.%s\n", t->base.name, c->base.name);
973 : return c;
974 : }
975 :
976 : sql_key *
977 7059 : mvc_bind_key(mvc *m, sql_schema *s, const char *kname)
978 : {
979 7059 : sql_key *k = schema_find_key(m->session->tr, s, kname);
980 :
981 7059 : if (!k)
982 : return NULL;
983 3 : TRC_DEBUG(SQL_TRANS, "Bind key: %s.%s\n", s->base.name, kname);
984 : return k;
985 : }
986 :
987 : sql_idx *
988 19545 : mvc_bind_idx(mvc *m, sql_schema *s, const char *iname)
989 : {
990 19545 : sql_idx *i = schema_find_idx(m->session->tr, s, iname);
991 :
992 19545 : if (!i)
993 : return NULL;
994 12276 : TRC_DEBUG(SQL_TRANS, "Bind index: %s.%s\n", s->base.name, iname);
995 : return i;
996 : }
997 :
998 : static int
999 912 : uniqueKey(sql_key *k)
1000 : {
1001 912 : return (k->type == pkey || k->type == ukey);
1002 : }
1003 :
1004 : sql_key *
1005 902 : mvc_bind_ukey(sql_table *t, list *colnames)
1006 : {
1007 902 : node *cn;
1008 902 : node *cur;
1009 902 : sql_key *res = NULL;
1010 902 : int len = list_length(colnames);
1011 :
1012 902 : if (ol_length(t->keys))
1013 914 : for (cur = ol_first_node(t->keys); cur; cur = cur->next) {
1014 912 : node *cc;
1015 912 : sql_key *k = cur->data;
1016 :
1017 912 : if (uniqueKey(k) && list_length(k->columns) == len) {
1018 902 : res = k;
1019 1827 : for (cc = k->columns->h, cn = colnames->h; cc && cn; cc = cc->next, cn = cn->next) {
1020 930 : sql_kc *c = cc->data;
1021 930 : char *n = cn->data;
1022 :
1023 930 : if (strcmp(c->c->base.name, n) != 0) {
1024 : res = NULL;
1025 : break;
1026 : }
1027 : }
1028 902 : if (res)
1029 : break;
1030 : }
1031 : }
1032 902 : return res;
1033 : }
1034 :
1035 : sql_trigger *
1036 926 : mvc_bind_trigger(mvc *m, sql_schema *s, const char *tname)
1037 : {
1038 926 : sql_trigger *t = schema_find_trigger(m->session->tr, s, tname);
1039 :
1040 926 : if (!t)
1041 : return NULL;
1042 167 : TRC_DEBUG(SQL_TRANS, "Bind trigger: %s.%s\n", s->base.name, tname);
1043 : return t;
1044 : }
1045 :
1046 : int
1047 898 : mvc_create_type(mvc *sql, sql_schema *s, const char *name, unsigned int digits, unsigned int scale, int radix, const char *impl)
1048 : {
1049 898 : TRC_DEBUG(SQL_TRANS, "Create type: %s\n", name);
1050 898 : return sql_trans_create_type(sql->session->tr, s, name, digits, scale, radix, impl);
1051 : }
1052 :
1053 : int
1054 3 : mvc_drop_type(mvc *m, sql_schema *s, sql_type *t, int drop_action)
1055 : {
1056 3 : TRC_DEBUG(SQL_TRANS, "Drop type: %s %s\n", s->base.name, t->base.name);
1057 3 : if (t)
1058 5 : return sql_trans_drop_type(m->session->tr, s, t->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1059 : return 0;
1060 : }
1061 :
1062 : int
1063 229272 : mvc_create_func(sql_func **f, mvc *m, sql_allocator *sa, sql_schema *s, const char *name, list *args, list *res, sql_ftype type, sql_flang lang,
1064 : const char *mod, const char *impl, const char *query, bit varres, bit vararg, bit system, bit side_effect)
1065 : {
1066 229272 : int lres = LOG_OK;
1067 :
1068 229272 : TRC_DEBUG(SQL_TRANS, "Create function: %s\n", name);
1069 229272 : if (sa) {
1070 114437 : *f = create_sql_func(m->store, sa, name, args, res, type, lang, mod, impl, query, varres, vararg, system, side_effect);
1071 114437 : (*f)->s = s;
1072 : } else
1073 114835 : lres = sql_trans_create_func(f, m->session->tr, s, name, args, res, type, lang, mod, impl, query, varres, vararg, system, side_effect);
1074 229272 : return lres;
1075 : }
1076 :
1077 : int
1078 634 : mvc_drop_func(mvc *m, sql_schema *s, sql_func *f, int drop_action)
1079 : {
1080 634 : TRC_DEBUG(SQL_TRANS, "Drop function: %s %s\n", s->base.name, f->base.name);
1081 1186 : return sql_trans_drop_func(m->session->tr, s, f->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1082 : }
1083 :
1084 : int
1085 28 : mvc_drop_all_func(mvc *m, sql_schema *s, list *list_func, int drop_action)
1086 : {
1087 28 : TRC_DEBUG(SQL_TRANS, "Drop all functions: %s %s\n", s->base.name, ((sql_func *) list_func->h->data)->base.name);
1088 56 : return sql_trans_drop_all_func(m->session->tr, s, list_func, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1089 : }
1090 :
1091 : int
1092 1075 : mvc_create_schema(mvc *m, const char *name, sqlid auth_id, sqlid owner)
1093 : {
1094 1075 : TRC_DEBUG(SQL_TRANS, "Create schema: %s %d %d\n", name, auth_id, owner);
1095 1075 : return sql_trans_create_schema(m->session->tr, name, auth_id, owner, NULL);
1096 : }
1097 :
1098 : int
1099 153 : mvc_drop_schema(mvc *m, sql_schema * s, int drop_action)
1100 : {
1101 153 : TRC_DEBUG(SQL_TRANS, "Drop schema: %s\n", s->base.name);
1102 229 : return sql_trans_drop_schema(m->session->tr, s->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1103 : }
1104 :
1105 : int
1106 5778 : mvc_create_ukey(sql_key **kres, mvc *m, sql_table *t, const char *name, key_type kt)
1107 : {
1108 5778 : int res = LOG_OK;
1109 :
1110 5778 : TRC_DEBUG(SQL_TRANS, "Create ukey: %s %u\n", t->base.name, (unsigned) kt);
1111 5778 : if (t->persistence == SQL_DECLARED_TABLE)
1112 5778 : *kres = create_sql_ukey(m->store, m->sa, t, name, kt);
1113 : else
1114 0 : res = sql_trans_create_ukey(kres, m->session->tr, t, name, kt);
1115 5778 : return res;
1116 : }
1117 :
1118 : int
1119 6697 : mvc_create_key_done(mvc *m, sql_key *k)
1120 : {
1121 6697 : int res = LOG_OK;
1122 :
1123 6697 : if (k->t->persistence == SQL_DECLARED_TABLE)
1124 6697 : key_create_done(m->session->tr, m->sa, k);
1125 : else
1126 0 : res = sql_trans_key_done(m->session->tr, k);
1127 6697 : return res;
1128 : }
1129 :
1130 : int
1131 938 : mvc_create_fkey(sql_fkey **kres, mvc *m, sql_table *t, const char *name, key_type kt, sql_key *rkey, int on_delete, int on_update)
1132 : {
1133 938 : int res = LOG_OK;
1134 :
1135 938 : TRC_DEBUG(SQL_TRANS, "Create fkey: %s %u %p\n", t->base.name, (unsigned) kt, rkey);
1136 938 : if (t->persistence == SQL_DECLARED_TABLE)
1137 938 : *kres = create_sql_fkey(m->store, m->sa, t, name, kt, rkey, on_delete, on_update);
1138 : else
1139 0 : res = sql_trans_create_fkey(kres, m->session->tr, t, name, kt, rkey, on_delete, on_update);
1140 938 : return res;
1141 : }
1142 :
1143 : int
1144 6366 : mvc_create_kc(mvc *m, sql_key *k, sql_column *c)
1145 : {
1146 6366 : int res = LOG_OK;
1147 :
1148 6366 : if (k->t->persistence == SQL_DECLARED_TABLE)
1149 6366 : create_sql_kc(m->store, m->sa, k, c);
1150 : else
1151 0 : res = sql_trans_create_kc(m->session->tr, k, c);
1152 6366 : return res;
1153 : }
1154 :
1155 : int
1156 957 : mvc_create_fkc(mvc *m, sql_fkey *fk, sql_column *c)
1157 : {
1158 957 : int res = LOG_OK;
1159 957 : sql_key *k = (sql_key*)fk;
1160 :
1161 957 : if (k->t->persistence == SQL_DECLARED_TABLE)
1162 957 : create_sql_kc(m->store, m->sa, k, c);
1163 : else
1164 0 : res = sql_trans_create_fkc(m->session->tr, fk, c);
1165 957 : return res;
1166 : }
1167 :
1168 : int
1169 143 : mvc_drop_key(mvc *m, sql_schema *s, sql_key *k, int drop_action)
1170 : {
1171 143 : TRC_DEBUG(SQL_TRANS, "Drop key: %s %s\n", s->base.name, k->base.name);
1172 143 : if (k->t->persistence == SQL_DECLARED_TABLE) {
1173 0 : drop_sql_key(k->t, k->base.id, drop_action);
1174 0 : return 0;
1175 : } else
1176 285 : return sql_trans_drop_key(m->session->tr, s, k->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1177 : }
1178 :
1179 : int
1180 331 : mvc_create_idx(sql_idx **i, mvc *m, sql_table *t, const char *name, idx_type it)
1181 : {
1182 331 : int res = LOG_OK;
1183 :
1184 331 : TRC_DEBUG(SQL_TRANS, "Create index: %s %u\n", t->base.name, (unsigned) it);
1185 331 : if (t->persistence == SQL_DECLARED_TABLE)
1186 : /* declared tables should not end up in the catalog */
1187 331 : *i = create_sql_idx(m->store, m->sa, t, name, it);
1188 : else
1189 0 : res = sql_trans_create_idx(i, m->session->tr, t, name, it);
1190 331 : return res;
1191 : }
1192 :
1193 : int
1194 423 : mvc_create_ic(mvc *m, sql_idx *i, sql_column *c)
1195 : {
1196 423 : int res = LOG_OK;
1197 :
1198 423 : if (i->t->persistence == SQL_DECLARED_TABLE)
1199 : /* declared tables should not end up in the catalog */
1200 423 : create_sql_ic(m->store, m->sa, i, c);
1201 : else
1202 0 : res = sql_trans_create_ic(m->session->tr, i, c);
1203 423 : return res;
1204 : }
1205 :
1206 : int
1207 329 : mvc_create_idx_done(mvc *m, sql_idx *i)
1208 : {
1209 329 : int res = LOG_OK;
1210 :
1211 329 : (void) m;
1212 329 : (void) create_sql_idx_done(m->session->tr, i);
1213 329 : return res;
1214 : }
1215 :
1216 : int
1217 160 : mvc_drop_idx(mvc *m, sql_schema *s, sql_idx *i)
1218 : {
1219 160 : TRC_DEBUG(SQL_TRANS, "Drop index: %s %s\n", s->base.name, i->base.name);
1220 160 : if (i->t->persistence == SQL_DECLARED_TABLE) {
1221 : /* declared tables should not end up in the catalog */
1222 0 : drop_sql_idx(i->t, i->base.id);
1223 0 : return 0;
1224 : } else
1225 160 : return sql_trans_drop_idx(m->session->tr, s, i->base.id, DROP_RESTRICT);
1226 : }
1227 :
1228 : int
1229 334 : mvc_create_trigger(sql_trigger **tri, mvc *m, sql_table *t, const char *name, sht time, sht orientation, sht event, const char *old_name,
1230 : const char *new_name, const char *condition, const char *statement)
1231 : {
1232 334 : TRC_DEBUG(SQL_TRANS, "Create trigger: %s %d %d %d\n", t->base.name, time, orientation, event);
1233 334 : return sql_trans_create_trigger(tri, m->session->tr, t, name, time, orientation, event, old_name, new_name, condition, statement);
1234 : }
1235 :
1236 : int
1237 86 : mvc_drop_trigger(mvc *m, sql_schema *s, sql_trigger *tri)
1238 : {
1239 86 : TRC_DEBUG(SQL_TRANS, "Drop trigger: %s %s\n", s->base.name, tri->base.name);
1240 86 : return sql_trans_drop_trigger(m->session->tr, s, tri->base.id, DROP_RESTRICT);
1241 : }
1242 :
1243 : int
1244 11028 : mvc_create_table(sql_table **t, mvc *m, sql_schema *s, const char *name, int tt, bit system, int persistence, int commit_action, int sz, bit properties)
1245 : {
1246 11028 : char *err = NULL;
1247 11028 : int res = LOG_OK;
1248 :
1249 11028 : assert(s);
1250 11028 : TRC_DEBUG(SQL_TRANS, "Create table: %s %s %d %d %d %d %d\n", s->base.name, name, tt, system, persistence, commit_action, (int)properties);
1251 11028 : if (persistence == SQL_DECLARED_TABLE) {
1252 9690 : *t = create_sql_table(m->store, m->sa, name, tt, system, persistence, commit_action, properties);
1253 9690 : (*t)->s = s;
1254 : } else {
1255 1338 : res = sql_trans_create_table(t, m->session->tr, s, name, NULL, tt, system, persistence, commit_action, sz, properties);
1256 1338 : if (res == LOG_OK && isPartitionedByExpressionTable(*t) && (err = bootstrap_partition_expression(m, *t, 1))) {
1257 0 : (void) sql_error(m, 02, "%s", err);
1258 0 : return -5;
1259 : }
1260 1338 : if (res == LOG_OK)
1261 1338 : res = sql_trans_set_partition_table(m->session->tr, *t);
1262 : }
1263 : return res;
1264 : }
1265 :
1266 : int
1267 22629 : mvc_create_view(sql_table **t, mvc *m, sql_schema *s, const char *name, int persistence, const char *sql, bit system)
1268 : {
1269 22629 : int res = LOG_OK;
1270 :
1271 22629 : TRC_DEBUG(SQL_TRANS, "Create view: %s %s %s\n", s->base.name, name, sql);
1272 22629 : if (persistence == SQL_DECLARED_TABLE) {
1273 22183 : *t = create_sql_table(m->store, m->sa, name, tt_view, system, persistence, 0, 0);
1274 22183 : (*t)->s = s;
1275 22183 : (*t)->query = sa_strdup(m->sa, sql);
1276 : } else {
1277 446 : res = sql_trans_create_table(t, m->session->tr, s, name, sql, tt_view, system, SQL_PERSIST, 0, 0, 0);
1278 : }
1279 22629 : return res;
1280 : }
1281 :
1282 : int
1283 94 : mvc_create_remote(sql_table **t, mvc *m, sql_schema *s, const char *name, int persistence, const char *loc)
1284 : {
1285 94 : int res = LOG_OK;
1286 :
1287 94 : TRC_DEBUG(SQL_TRANS, "Create remote: %s %s %s\n", s->base.name, name, loc);
1288 94 : if (persistence == SQL_DECLARED_TABLE) {
1289 94 : *t = create_sql_table(m->store, m->sa, name, tt_remote, 0, persistence, 0, 0);
1290 94 : (*t)->s = s;
1291 94 : (*t)->query = sa_strdup(m->sa, loc);
1292 : } else {
1293 0 : res = sql_trans_create_table(t, m->session->tr, s, name, loc, tt_remote, 0, SQL_REMOTE, 0, 0, 0);
1294 : }
1295 94 : return res;
1296 : }
1297 :
1298 : static str
1299 30 : remote_drop(mvc *m, sql_table *t)
1300 : {
1301 30 : sqlid id = t->base.id;
1302 30 : int log_res = 0;
1303 30 : sql_trans *tr = m->session->tr;
1304 30 : sqlstore *store = tr->store;
1305 30 : sql_schema *sys = find_sql_schema(tr, "sys");
1306 30 : sql_table *remote_user_info = find_sql_table(tr, sys, REMOTE_USER_INFO);
1307 30 : sql_column *remote_user_info_id = find_sql_column(remote_user_info, "table_id");
1308 30 : oid rid = store->table_api.column_find_row(tr, remote_user_info_id, &id, NULL);
1309 30 : if (is_oid_nil(rid)) {
1310 1 : TRC_WARNING(SQL_TRANS, "Drop table: %s %s no remote info\n", t->s->base.name, t->base.name);
1311 29 : } else if ((log_res = store->table_api.table_delete(tr, remote_user_info, rid)) != 0)
1312 0 : throw(SQL, "sql.drop_table", SQLSTATE(42000) "Drop table failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
1313 : return MAL_SUCCEED;
1314 : }
1315 :
1316 : str
1317 3769 : mvc_drop_table(mvc *m, sql_schema *s, sql_table *t, int drop_action)
1318 : {
1319 3769 : char *msg = NULL;
1320 3769 : TRC_DEBUG(SQL_TRANS, "Drop table: %s %s\n", s->base.name, t->base.name);
1321 :
1322 3769 : if (isRemote(t) && (msg = remote_drop(m, t)) != NULL)
1323 : return msg;
1324 :
1325 7153 : switch (sql_trans_drop_table(m->session->tr, s, t->base.name, drop_action ? DROP_CASCADE_START : DROP_RESTRICT)) {
1326 0 : case -1:
1327 0 : throw(SQL,"sql.mvc_drop_table",SQLSTATE(HY013) MAL_MALLOC_FAIL);
1328 0 : case -2:
1329 : case -3:
1330 0 : throw(SQL, "sql.mvc_drop_table", SQLSTATE(42000) "Transaction conflict while dropping table %s.%s", s->base.name, t->base.name);
1331 : default:
1332 : break;
1333 : }
1334 : return MAL_SUCCEED;
1335 : }
1336 :
1337 : BUN
1338 41811 : mvc_clear_table(mvc *m, sql_table *t)
1339 : {
1340 41811 : return sql_trans_clear_table(m->session->tr, t);
1341 : }
1342 :
1343 : int
1344 9589 : mvc_create_column_(sql_column **col, mvc *m, sql_table *t, const char *name, const char *type, unsigned int digits)
1345 : {
1346 9589 : sql_subtype tpe;
1347 :
1348 9589 : if (!sql_find_subtype(&tpe, type, digits, 0))
1349 : return -1;
1350 :
1351 9589 : return sql_trans_create_column(col, m->session->tr, t, name, &tpe);
1352 : }
1353 :
1354 : int
1355 253238 : mvc_create_column(sql_column **col, mvc *m, sql_table *t, const char *name, sql_subtype *tpe)
1356 : {
1357 253238 : int res = LOG_OK;
1358 :
1359 253238 : TRC_DEBUG(SQL_TRANS, "Create column: %s %s %s\n", t->base.name, name, tpe->type->base.name);
1360 253238 : if (t->persistence == SQL_DECLARED_TABLE)
1361 : /* declared tables should not end up in the catalog */
1362 253238 : *col = create_sql_column(m->store, m->sa, t, name, tpe);
1363 : else
1364 0 : res = sql_trans_create_column(col, m->session->tr, t, name, tpe);
1365 253238 : return res;
1366 : }
1367 :
1368 : int
1369 136 : mvc_drop_column(mvc *m, sql_table *t, sql_column *col, int drop_action)
1370 : {
1371 136 : TRC_DEBUG(SQL_TRANS, "Drop column: %s %s\n", t->base.name, col->base.name);
1372 136 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1373 68 : drop_sql_column(t, col->base.id, drop_action);
1374 68 : return 0;
1375 : } else
1376 128 : return sql_trans_drop_column(m->session->tr, t, col->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1377 : }
1378 :
1379 : int
1380 365364 : mvc_create_dependency(mvc *m, sql_base *b, sqlid depend_id, sql_dependency depend_type)
1381 : {
1382 365364 : int res = LOG_OK;
1383 :
1384 365364 : TRC_DEBUG(SQL_TRANS, "Create dependency: %d %d %d\n", b->id, depend_id, (int) depend_type);
1385 365364 : if ( (b->id != depend_id) || (depend_type == BEDROPPED_DEPENDENCY) ) {
1386 365363 : if (!b->new)
1387 219441 : res = sql_trans_add_dependency(m->session->tr, b->id, ddl);
1388 219441 : if (res == LOG_OK)
1389 365363 : res = sql_trans_create_dependency(m->session->tr, b->id, depend_id, depend_type);
1390 : }
1391 365364 : return res;
1392 : }
1393 :
1394 : int
1395 138322 : mvc_create_dependencies(mvc *m, list *blist, sqlid depend_id, sql_dependency dep_type)
1396 : {
1397 138322 : int res = LOG_OK;
1398 :
1399 138322 : TRC_DEBUG(SQL_TRANS, "Create dependencies on '%d' of type: %d\n", depend_id, (int) dep_type);
1400 138322 : if (!list_empty(blist)) {
1401 378513 : for (node *n = blist->h ; n && res == LOG_OK ; n = n->next) {
1402 351934 : sql_base *b = n->data;
1403 351934 : if (!b->new) /* only add old objects to the transaction dependency list */
1404 219391 : res = sql_trans_add_dependency(m->session->tr, b->id, ddl);
1405 351934 : if (res == LOG_OK)
1406 351934 : res = mvc_create_dependency(m, b, depend_id, dep_type);
1407 : }
1408 : }
1409 138322 : return res;
1410 : }
1411 :
1412 : int
1413 4472 : mvc_check_dependency(mvc *m, sqlid id, sql_dependency type, list *ignore_ids)
1414 : {
1415 4472 : list *dep_list = NULL;
1416 :
1417 4472 : TRC_DEBUG(SQL_TRANS, "Check dependency on: %d\n", id);
1418 4472 : switch (type) {
1419 104 : case OWNER_DEPENDENCY:
1420 104 : dep_list = sql_trans_owner_schema_dependencies(m->session->tr, id);
1421 104 : break;
1422 0 : case SCHEMA_DEPENDENCY:
1423 0 : dep_list = sql_trans_schema_user_dependencies(m->session->tr, id);
1424 0 : break;
1425 3275 : case TABLE_DEPENDENCY:
1426 3275 : dep_list = sql_trans_get_dependencies(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1427 3275 : break;
1428 226 : case VIEW_DEPENDENCY:
1429 226 : dep_list = sql_trans_get_dependencies(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1430 226 : break;
1431 596 : case FUNC_DEPENDENCY:
1432 : case PROC_DEPENDENCY:
1433 596 : dep_list = sql_trans_get_dependencies(m->session->tr, id, FUNC_DEPENDENCY, ignore_ids);
1434 596 : break;
1435 271 : default:
1436 271 : dep_list = sql_trans_get_dependencies(m->session->tr, id, COLUMN_DEPENDENCY, NULL);
1437 : }
1438 :
1439 4472 : if (!dep_list)
1440 : return DEPENDENCY_CHECK_ERROR;
1441 :
1442 4472 : if (list_length(dep_list) >= 2) {
1443 48 : list_destroy(dep_list);
1444 48 : return HAS_DEPENDENCY;
1445 : }
1446 :
1447 4424 : list_destroy(dep_list);
1448 4424 : return NO_DEPENDENCY;
1449 : }
1450 :
1451 : int
1452 16637 : mvc_null(mvc *m, sql_column *col, int isnull)
1453 : {
1454 16637 : TRC_DEBUG(SQL_TRANS, "Null: %s %d\n", col->base.name, isnull);
1455 16637 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1456 16540 : col->null = isnull;
1457 16540 : return 0;
1458 : }
1459 97 : return sql_trans_alter_null(m->session->tr, col, isnull);
1460 : }
1461 :
1462 : int
1463 1417 : mvc_default(mvc *m, sql_column *col, char *val)
1464 : {
1465 1417 : TRC_DEBUG(SQL_TRANS, "Default: %s %s\n", col->base.name, val);
1466 1417 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1467 1398 : col->def = val?sa_strdup(m->sa, val):NULL;
1468 1398 : return 0;
1469 : } else {
1470 19 : return sql_trans_alter_default(m->session->tr, col, val);
1471 : }
1472 : }
1473 :
1474 : int
1475 5 : mvc_drop_default(mvc *m, sql_column *col)
1476 : {
1477 5 : TRC_DEBUG(SQL_TRANS, "Drop default: %s\n", col->base.name);
1478 5 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1479 5 : col->def = NULL;
1480 5 : return 0;
1481 : } else {
1482 0 : return sql_trans_alter_default(m->session->tr, col, NULL);
1483 : }
1484 : }
1485 :
1486 : int
1487 0 : mvc_storage(mvc *m, sql_column *col, char *storage)
1488 : {
1489 0 : TRC_DEBUG(SQL_TRANS, "Storage: %s %s\n", col->base.name, storage);
1490 0 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1491 0 : col->storage_type = storage?sa_strdup(m->sa, storage):NULL;
1492 0 : return 0;
1493 : } else {
1494 0 : return sql_trans_alter_storage(m->session->tr, col, storage);
1495 : }
1496 : }
1497 :
1498 : int
1499 2066 : mvc_access(mvc *m, sql_table *t, sht access)
1500 : {
1501 2066 : TRC_DEBUG(SQL_TRANS, "Access: %s %d\n", t->base.name, access);
1502 2066 : if (t->persistence == SQL_DECLARED_TABLE) {
1503 0 : t->access = access;
1504 0 : return 0;
1505 : }
1506 2066 : return sql_trans_alter_access(m->session->tr, t, access);
1507 : }
1508 :
1509 : int
1510 24175 : mvc_is_sorted(mvc *m, sql_column *col)
1511 : {
1512 24175 : TRC_DEBUG(SQL_TRANS, "Is sorted: %s\n", col->base.name);
1513 24175 : return sql_trans_is_sorted(m->session->tr, col);
1514 : }
1515 :
1516 : int
1517 7901 : mvc_is_unique(mvc *m, sql_column *col)
1518 : {
1519 7901 : TRC_DEBUG(SQL_TRANS, "Is unique: %s\n", col->base.name);
1520 7901 : return sql_trans_is_unique(m->session->tr, col);
1521 : }
1522 :
1523 : int
1524 1892 : mvc_is_duplicate_eliminated(mvc *m, sql_column *col)
1525 : {
1526 1892 : TRC_DEBUG(SQL_TRANS, "Is duplicate eliminated: %s\n", col->base.name);
1527 1892 : return sql_trans_is_duplicate_eliminated(m->session->tr, col);
1528 : }
1529 :
1530 : int
1531 776820 : mvc_col_stats(mvc *m, sql_column *col, bool *nonil, bool *unique, double *unique_est, ValPtr min, ValPtr max)
1532 : {
1533 776820 : TRC_DEBUG(SQL_TRANS, "Retrieving column stats for: %s\n", col->base.name);
1534 776820 : return sql_trans_col_stats(m->session->tr, col, nonil, unique, unique_est, min, max);
1535 : }
1536 :
1537 : int
1538 252855 : mvc_copy_column(mvc *m, sql_table *t, sql_column *c, sql_column **cres)
1539 : {
1540 252855 : return sql_trans_copy_column(m->session->tr, t, c, cres);
1541 : }
1542 :
1543 : int
1544 6674 : mvc_copy_key(mvc *m, sql_table *t, sql_key *k, sql_key **kres)
1545 : {
1546 6674 : return sql_trans_copy_key(m->session->tr, t, k, kres);
1547 : }
1548 :
1549 : int
1550 6997 : mvc_copy_idx(mvc *m, sql_table *t, sql_idx *i, sql_idx **ires)
1551 : {
1552 6997 : return sql_trans_copy_idx(m->session->tr, t, i, ires);
1553 : }
1554 :
1555 : int
1556 0 : mvc_copy_trigger(mvc *m, sql_table *t, sql_trigger *tr, sql_trigger **tres)
1557 : {
1558 0 : return sql_trans_copy_trigger(m->session->tr, t, tr, tres);
1559 : }
1560 :
1561 : sql_rel *
1562 686797 : sql_processrelation(mvc *sql, sql_rel *rel, int profile, int instantiate, int value_based_opt, int storage_based_opt)
1563 : {
1564 686797 : if (rel)
1565 686797 : rel = rel_unnest(sql, rel);
1566 686779 : if (rel)
1567 686763 : rel = rel_optimizer(sql, rel, profile, instantiate, value_based_opt, storage_based_opt);
1568 686790 : return rel;
1569 : }
1570 :
1571 : static inline int dlist_cmp(mvc *sql, dlist *l1, dlist *l2);
1572 :
1573 : static inline int
1574 537 : dnode_cmp(mvc *sql, dnode *d1, dnode *d2)
1575 : {
1576 537 : if (d1 == d2)
1577 : return 0;
1578 :
1579 537 : if (!d1 || !d2)
1580 : return -1;
1581 :
1582 537 : if (d1->type == d2->type) {
1583 537 : switch (d1->type) {
1584 39 : case type_int:
1585 39 : return (d1->data.i_val - d2->data.i_val);
1586 0 : case type_lng: {
1587 0 : lng c = d1->data.l_val - d2->data.l_val;
1588 0 : assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
1589 0 : return (int) c;
1590 : }
1591 301 : case type_string:
1592 301 : if (d1->data.sval == d2->data.sval)
1593 : return 0;
1594 301 : if (!d1->data.sval || !d2->data.sval)
1595 : return -1;
1596 301 : return strcmp(d1->data.sval, d2->data.sval);
1597 99 : case type_list:
1598 99 : return dlist_cmp(sql, d1->data.lval, d2->data.lval);
1599 98 : case type_symbol:
1600 98 : return symbol_cmp(sql, d1->data.sym, d2->data.sym);
1601 0 : case type_type:
1602 0 : return subtype_cmp(&d1->data.typeval, &d2->data.typeval);
1603 : default:
1604 0 : assert(0);
1605 : }
1606 : }
1607 : return -1;
1608 : }
1609 :
1610 : static inline int
1611 404 : dlist_cmp(mvc *sql, dlist *l1, dlist *l2)
1612 : {
1613 404 : int res = 0;
1614 404 : dnode *d1, *d2;
1615 :
1616 404 : if (l1 == l2)
1617 : return 0;
1618 :
1619 404 : if (!l1 || !l2 || dlist_length(l1) != dlist_length(l2))
1620 28 : return -1;
1621 :
1622 913 : for (d1 = l1->h, d2 = l2->h; !res && d1; d1 = d1->next, d2 = d2->next) {
1623 537 : res = dnode_cmp(sql, d1, d2);
1624 : }
1625 : return res;
1626 : }
1627 :
1628 : static inline int
1629 132 : AtomNodeCmp(AtomNode *a1, AtomNode *a2)
1630 : {
1631 132 : if (a1 == a2)
1632 : return 0;
1633 132 : if (!a1 || !a2)
1634 : return -1;
1635 132 : if (a1->a && a2->a)
1636 132 : return atom_cmp(a1->a, a2->a);
1637 : return -1;
1638 : }
1639 :
1640 : static inline int
1641 0 : SelectNodeCmp(mvc *sql, SelectNode *s1, SelectNode *s2)
1642 : {
1643 0 : if (s1 == s2)
1644 : return 0;
1645 0 : if (!s1 || !s2)
1646 : return -1;
1647 :
1648 0 : if (symbol_cmp(sql, s1->limit, s2->limit) == 0 &&
1649 0 : symbol_cmp(sql, s1->offset, s2->offset) == 0 &&
1650 0 : symbol_cmp(sql, s1->sample, s2->sample) == 0 &&
1651 0 : symbol_cmp(sql, s1->seed, s2->seed) == 0 &&
1652 0 : s1->distinct == s2->distinct &&
1653 0 : s1->lateral == s2->lateral &&
1654 0 : symbol_cmp(sql, s1->name, s2->name) == 0 &&
1655 0 : symbol_cmp(sql, s1->orderby, s2->orderby) == 0 &&
1656 0 : symbol_cmp(sql, s1->having, s2->having) == 0 &&
1657 0 : symbol_cmp(sql, s1->groupby, s2->groupby) == 0 &&
1658 0 : symbol_cmp(sql, s1->where, s2->where) == 0 &&
1659 0 : symbol_cmp(sql, s1->from, s2->from) == 0 &&
1660 0 : symbol_cmp(sql, s1->window, s2->window) == 0 &&
1661 0 : dlist_cmp(sql, s1->selection, s2->selection) == 0)
1662 : return 0;
1663 : return -1;
1664 : }
1665 :
1666 : static inline int
1667 455 : _symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
1668 : {
1669 455 : if (s1 == s2)
1670 : return 0;
1671 455 : if (!s1 || !s2)
1672 : return -1;
1673 455 : if (s1->token != s2->token || s1->type != s2->type)
1674 : return -1;
1675 439 : switch (s1->type) {
1676 0 : case type_int:
1677 0 : return (s1->data.i_val - s2->data.i_val);
1678 0 : case type_lng: {
1679 0 : lng c = s1->data.l_val - s2->data.l_val;
1680 0 : assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
1681 0 : return (int) c;
1682 : }
1683 2 : case type_string:
1684 2 : if (s1->data.sval == s2->data.sval)
1685 : return 0;
1686 0 : if (!s1->data.sval || !s2->data.sval)
1687 : return -1;
1688 0 : return strcmp(s1->data.sval, s2->data.sval);
1689 305 : case type_list: {
1690 305 : return dlist_cmp(sql, s1->data.lval, s2->data.lval);
1691 : }
1692 0 : case type_type:
1693 0 : return subtype_cmp(&s1->data.typeval, &s2->data.typeval);
1694 132 : case type_symbol:
1695 132 : if (s1->token == SQL_SELECT) {
1696 0 : if (s2->token != SQL_SELECT)
1697 : return -1;
1698 0 : return SelectNodeCmp(sql, (SelectNode *) s1, (SelectNode *) s2);
1699 132 : } else if (s1->token == SQL_ATOM) {
1700 132 : if (s2->token != SQL_ATOM)
1701 : return -1;
1702 132 : return AtomNodeCmp((AtomNode *) s1, (AtomNode *) s2);
1703 : } else {
1704 0 : return symbol_cmp(sql, s1->data.sym, s2->data.sym);
1705 : }
1706 : default:
1707 0 : assert(0);
1708 : }
1709 : return 0; /* never reached, just to pacify compilers */
1710 : }
1711 :
1712 : int
1713 455 : symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
1714 : {
1715 455 : return _symbol_cmp(sql, s1, s2);
1716 : }
|