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 225 : sql_create_comments(mvc *m, sql_schema *s)
40 : {
41 225 : sql_table *t = NULL;
42 225 : sql_column *c = NULL;
43 225 : sql_key *k = NULL;
44 :
45 225 : mvc_create_table(&t, m, s, "comments", tt_table, 1, SQL_PERSIST, 0, -1, 0);
46 225 : mvc_create_column_(&c, m, t, "id", "int", 32);
47 225 : sql_trans_create_ukey(&k, m->session->tr, t, "comments_id_pkey", pkey, NULL);
48 225 : sql_trans_create_kc(m->session->tr, k, c);
49 225 : sql_trans_key_done(m->session->tr, k);
50 225 : sql_trans_create_dependency(m->session->tr, c->base.id, k->idx->base.id, INDEX_DEPENDENCY);
51 225 : mvc_create_column_(&c, m, t, "remark", "varchar", 65000);
52 225 : sql_trans_alter_null(m->session->tr, c, 0);
53 225 : }
54 :
55 : static sql_table *
56 466 : mvc_init_create_view(mvc *m, sql_schema *s, const char *name, const char *query)
57 : {
58 466 : sql_table *t = NULL;
59 :
60 466 : mvc_create_view(&t, m, s, name, SQL_PERSIST, query, 1);
61 466 : if (t) {
62 466 : char *buf;
63 466 : sql_rel *r = NULL;
64 :
65 466 : 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 466 : r = rel_parse(m, s, buf, m_deps);
71 466 : if (r)
72 466 : r = sql_processrelation(m, r, 0, 0, 0, 0);
73 466 : if (r) {
74 466 : list *blist = rel_dependencies(m, r);
75 466 : 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 466 : sa_reset(m->ta);
82 466 : assert(r);
83 : }
84 466 : 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 32 : mvc_fix_depend(mvc *m, sql_column *depids, struct view_t *v, int n)
116 : {
117 32 : sqlstore *store = m->store;
118 32 : oid rid;
119 32 : rids *rs;
120 :
121 368 : for (int i = 0; i < n; i++) {
122 672 : rs = store->table_api.rids_select(m->session->tr, depids,
123 336 : &v[i].oldid, &v[i].oldid, NULL);
124 336 : if (rs) {
125 2144 : while ((rid = store->table_api.rids_next(rs)), !is_oid_nil(rid)) {
126 1808 : store->table_api.column_update_value(m->session->tr, depids, rid, &v[i].newid);
127 : }
128 336 : store->table_api.rids_destroy(rs);
129 : }
130 : }
131 32 : }
132 :
133 : sql_store
134 327 : mvc_init(int debug, store_type store_tpe, int ro, int su, const char *initpasswd)
135 : {
136 327 : sqlstore *store = NULL;
137 327 : sql_schema *s;
138 327 : sql_table *t;
139 327 : mvc *m;
140 327 : str msg;
141 :
142 327 : TRC_DEBUG(SQL_TRANS, "Initialization\n");
143 327 : keyword_init();
144 327 : if (scanner_init_keywords() != 0) {
145 0 : TRC_CRITICAL(SQL_TRANS, "Malloc failure\n");
146 0 : return NULL;
147 : }
148 :
149 327 : 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 326 : initialize_sql_functions_lookup(store->sa);
156 :
157 326 : m = mvc_create((sql_store)store, store->sa, 0, 0, NULL, NULL);
158 326 : if (!m) {
159 0 : mvc_exit(store);
160 0 : TRC_CRITICAL(SQL_TRANS, "Malloc failure\n");
161 0 : return NULL;
162 : }
163 :
164 326 : assert(m->sa == NULL);
165 326 : m->sa = sa_create(m->pa);
166 326 : 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 326 : if (store->first || store->catalog_version) {
174 233 : sqlid tid = 0, cid = 0;
175 233 : 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 233 : }, 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 233 : 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 233 : s = m->session->schema = mvc_bind_schema(m, "sys");
286 233 : assert(m->session->schema != NULL);
287 :
288 233 : if (!store->first) {
289 80 : MVC_INIT_DROP_TABLE(tid, "tables", tview, 9);
290 88 : MVC_INIT_DROP_TABLE(cid, "columns", cview, 10);
291 : }
292 :
293 233 : 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 233 : 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 2330 : for (int i = 0; i < 9; i++) {
302 2097 : sql_column *col = NULL;
303 :
304 2097 : mvc_create_column_(&col, m, t, tview[i].name, tview[i].type, tview[i].digits);
305 2097 : 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 2097 : tview[i].newid = col->base.id;
313 : }
314 :
315 233 : if (!store->first) {
316 8 : int pub = ROLE_PUBLIC;
317 8 : int p = PRIV_SELECT;
318 8 : int zero = 0;
319 8 : sql_table *privs = find_sql_table(m->session->tr, s, "privileges");
320 8 : sql_table *deps = find_sql_table(m->session->tr, s, "dependencies");
321 8 : store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
322 8 : assert(tview[9].name == NULL);
323 8 : tview[9].oldid = tid;
324 8 : tview[9].newid = t->base.id;
325 8 : mvc_fix_depend(m, find_sql_column(deps, "id"), tview, 10);
326 8 : mvc_fix_depend(m, find_sql_column(deps, "depend_id"), tview, 10);
327 : }
328 :
329 233 : 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 233 : 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 2563 : for (int i = 0; i < 10; i++) {
337 2330 : sql_column *col = NULL;
338 :
339 2330 : mvc_create_column_(&col, m, t, cview[i].name, cview[i].type, cview[i].digits);
340 2330 : 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 2330 : cview[i].newid = col->base.id;
348 : }
349 :
350 233 : if (!store->first) {
351 8 : int pub = ROLE_PUBLIC;
352 8 : int p = PRIV_SELECT;
353 8 : int zero = 0;
354 8 : sql_table *privs = find_sql_table(m->session->tr, s, "privileges");
355 8 : sql_table *deps = find_sql_table(m->session->tr, s, "dependencies");
356 8 : store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
357 8 : assert(cview[10].name == NULL);
358 8 : cview[10].oldid = cid;
359 8 : cview[10].newid = t->base.id;
360 8 : mvc_fix_depend(m, find_sql_column(deps, "id"), cview, 11);
361 8 : mvc_fix_depend(m, find_sql_column(deps, "depend_id"), cview, 11);
362 : } else {
363 225 : sql_create_env(m, s);
364 225 : sql_create_comments(m, s);
365 225 : sql_create_privileges(m, s, initpasswd);
366 : }
367 :
368 233 : 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 326 : 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 326 : struct os_iter si;
387 326 : os_iterator(&si, m->session->tr->cat->schemas, m->session->tr, NULL);
388 1741 : for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
389 1415 : sql_schema *ss = (sql_schema*)b;
390 1415 : struct os_iter oi;
391 1415 : os_iterator(&oi, ss->tables, m->session->tr, NULL);
392 22815 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
393 21400 : sql_table *tt = (sql_table*)b;
394 21400 : 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 326 : 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 326 : 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 326 : mvc_destroy(m);
421 326 : return store;
422 : }
423 :
424 : void
425 325 : mvc_exit(sql_store store)
426 : {
427 325 : TRC_DEBUG(SQL_TRANS, "MVC exit\n");
428 325 : store_exit(store);
429 325 : keyword_exit();
430 325 : }
431 :
432 : void
433 325 : mvc_logmanager(sql_store store)
434 : {
435 325 : store_manager(store);
436 324 : }
437 :
438 : int
439 1465932 : mvc_status(mvc *m)
440 : {
441 1465932 : int res = m->session->status;
442 :
443 1465932 : 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 64523 : mvc_debug_on(mvc *m, int flg)
467 : {
468 :
469 64523 : 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 220546 : mvc_trans(mvc *m)
483 : {
484 220546 : int res = 0, err = m->session->status;
485 220546 : assert(!m->session->tr->active); /* can only start a new transaction */
486 :
487 220546 : TRC_INFO(SQL_TRANS, "Starting transaction\n");
488 220546 : res = sql_trans_begin(m->session);
489 220550 : if (m->qc && (res || err))
490 28959 : qc_restart(m->qc);
491 220550 : return res;
492 : }
493 :
494 : str
495 157979 : mvc_commit(mvc *m, int chain, const char *name, bool enabling_auto_commit)
496 : {
497 157979 : sql_trans *tr = m->session->tr;
498 157979 : int ok = SQL_OK;
499 157979 : str msg = MAL_SUCCEED, other;
500 157979 : char operation[BUFSIZ];
501 :
502 157979 : assert(tr);
503 157979 : assert(m->session->tr->active); /* only commit an active transaction */
504 157979 : TRC_DEBUG(SQL_TRANS,"Commit: %s\n", (name) ? name : "");
505 157979 : if(enabling_auto_commit)
506 1 : snprintf(operation, BUFSIZ, "Commit failed while enabling auto_commit: ");
507 157978 : else if(name)
508 46 : snprintf(operation, BUFSIZ, "SAVEPOINT: (%s)", name);
509 : else
510 157932 : snprintf(operation, BUFSIZ, "COMMIT:");
511 :
512 157979 : 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 157967 : if (name && name[0] != '\0') {
521 46 : sql_trans *tr = m->session->tr;
522 46 : TRC_DEBUG(SQL_TRANS, "Savepoint\n");
523 46 : 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 46 : 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 46 : m->type = Q_TRANS;
531 46 : TRC_INFO(SQL_TRANS, "Savepoint commit '%s' done\n", name);
532 46 : return msg;
533 : }
534 :
535 157921 : if (!tr->parent && !name) {
536 157916 : lng Tbegin = 0;
537 157916 : ulng ts_start = 0;
538 157916 : bool log_usec = profilerMode == 0 || m->session->auto_commit;
539 157916 : if(profilerStatus > 0) {
540 0 : if (log_usec) Tbegin = GDKusec();
541 0 : ts_start = m->session->tr->ts;
542 : }
543 :
544 157916 : const int state = sql_trans_end(m->session, ok);
545 :
546 157916 : 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 157916 : switch (state) {
554 0 : case SQL_ERR:
555 0 : GDKfatal("%s transaction commit failed; exiting (kernel error: %s)", operation, GDKerrbuf);
556 897 : break;
557 897 : case SQL_CONFLICT:
558 :
559 : /* transaction conflict */
560 897 : return createException(SQL, "sql.commit", SQLSTATE(40001) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
561 : default:
562 157019 : break;
563 : }
564 157019 : 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 157019 : m->type = Q_TRANS;
570 157019 : TRC_INFO(SQL_TRANS,
571 : "Commit done\n");
572 157019 : return msg;
573 : }
574 :
575 : /* save points only */
576 : assert(name || tr->parent);
577 :
578 : /* commit and cleanup nested transactions */
579 5 : if (tr->parent) {
580 12 : while (tr->parent != NULL && ok == SQL_OK) {
581 7 : 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 62470 : mvc_rollback(mvc *m, int chain, const char *name, bool disabling_auto_commit)
639 : {
640 62470 : str msg = MAL_SUCCEED;
641 :
642 62470 : TRC_DEBUG(SQL_TRANS, "Rollback: %s\n", (name) ? name : "");
643 62470 : (void) disabling_auto_commit;
644 :
645 62470 : sql_trans *tr = m->session->tr;
646 62470 : assert(m->session->tr && m->session->tr->active); /* only abort an active transaction */
647 62470 : 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 62468 : while (tr->parent != NULL)
677 16 : m->session-> tr = tr = sql_trans_destroy(tr);
678 : /* make sure we do not reuse changed data */
679 62452 : if (!list_empty(tr->changes))
680 1119 : tr->status = 1;
681 :
682 :
683 62452 : lng Tbegin = 0;
684 62452 : ulng ts_start = 0;
685 62452 : bool log_usec = profilerMode == 0 || m->session->auto_commit;
686 62452 : if(profilerStatus > 0) {
687 0 : if (log_usec) Tbegin = GDKusec();
688 0 : ts_start = m->session->tr->ts;
689 : }
690 62452 : (void) sql_trans_end(m->session, SQL_ERR);
691 :
692 62452 : 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 62452 : 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 62466 : if (msg != MAL_SUCCEED) {
709 : m->session->status = -1;
710 : return msg;
711 : }
712 62466 : m->type = Q_TRANS;
713 62466 : 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 76942 : _free(void *dummy, void *data)
766 : {
767 76942 : (void)dummy;
768 76942 : GDKfree(data);
769 76941 : }
770 :
771 : mvc *
772 38815 : mvc_create(sql_store *store, allocator *pa, int clientid, int debug, bstream *rs, stream *ws)
773 : {
774 38815 : mvc *m;
775 38815 : str sys_str = NULL;
776 :
777 38815 : assert(pa);
778 38815 : m = SA_ZNEW(pa, mvc);
779 38815 : if (!m)
780 : return NULL;
781 :
782 38815 : TRC_DEBUG(SQL_TRANS, "MVC create\n");
783 :
784 38815 : m->errstr[0] = '\0';
785 : /* if an error exceeds the buffer we don't want garbage at the end */
786 38815 : m->errstr[ERRSIZE-1] = '\0';
787 :
788 38815 : m->qc = qc_create(pa, clientid, 0);
789 38815 : if (!m->qc) {
790 : return NULL;
791 : }
792 38815 : m->pa = pa;
793 38815 : m->sa = NULL;
794 38815 : m->ta = sa_create(m->pa);
795 : #ifdef __has_builtin
796 : #if __has_builtin(__builtin_frame_address)
797 38815 : m->sp = (uintptr_t) __builtin_frame_address(0);
798 : #define BUILTIN_USED
799 : #endif
800 : #endif
801 : #ifndef BUILTIN_USED
802 : m->sp = (uintptr_t)(&m);
803 : #endif
804 : #undef BUILTIN_USED
805 :
806 38815 : m->params = NULL;
807 38815 : m->sizeframes = MAXPARAMS;
808 38815 : m->frames = SA_NEW_ARRAY(pa, sql_frame*, m->sizeframes);
809 38815 : m->topframes = 0;
810 38815 : m->frame = 0;
811 :
812 38815 : m->use_views = false;
813 38815 : if (!m->frames) {
814 0 : qc_destroy(m->qc);
815 0 : return NULL;
816 : }
817 38815 : if (init_global_variables(m) < 0) {
818 0 : qc_destroy(m->qc);
819 0 : list_destroy(m->global_vars);
820 0 : return NULL;
821 : }
822 38815 : m->sym = NULL;
823 :
824 38815 : m->role_id = m->user_id = -1;
825 38815 : m->timezone = 0;
826 38815 : m->sql_optimizer = INT_MAX;
827 38815 : m->clientid = clientid;
828 :
829 38815 : m->emode = m_normal;
830 38815 : m->emod = mod_none;
831 38815 : m->reply_size = 100;
832 38815 : m->debug = debug;
833 :
834 38815 : m->label = 0;
835 38815 : m->nid = 1;
836 38815 : m->cascade_action = NULL;
837 38815 : m->runs = NULL;
838 :
839 38815 : if (!(m->schema_path = list_create((fdestroy)_free))) {
840 0 : qc_destroy(m->qc);
841 0 : list_destroy(m->global_vars);
842 0 : return NULL;
843 : }
844 38815 : if (!(sys_str = _STRDUP("sys")) || !list_append(m->schema_path, sys_str)) {
845 0 : _DELETE(sys_str);
846 0 : qc_destroy(m->qc);
847 0 : list_destroy(m->global_vars);
848 0 : list_destroy(m->schema_path);
849 0 : return NULL;
850 : }
851 38815 : m->schema_path_has_sys = true;
852 38815 : m->schema_path_has_tmp = false;
853 38815 : m->no_int128 = false;
854 38815 : m->store = store;
855 :
856 38815 : m->session = sql_session_create(m->store, m->pa, 1 /*autocommit on*/);
857 38815 : if (!m->session) {
858 0 : qc_destroy(m->qc);
859 0 : list_destroy(m->global_vars);
860 0 : list_destroy(m->schema_path);
861 0 : return NULL;
862 : }
863 :
864 38815 : m->type = Q_PARSE;
865 :
866 38815 : scanner_init(&m->scanner, rs, ws);
867 38815 : return m;
868 : }
869 :
870 : void
871 38815 : mvc_destroy(mvc *m)
872 : {
873 38815 : sql_trans *tr;
874 :
875 38815 : TRC_DEBUG(SQL_TRANS, "MVC destroy\n");
876 38815 : tr = m->session->tr;
877 38815 : if (tr) {
878 38815 : if (m->session->tr->active)
879 0 : (void)sql_trans_end(m->session, SQL_ERR);
880 38815 : while (tr->parent)
881 0 : m->session->tr = tr = sql_trans_destroy(tr);
882 : }
883 38815 : sql_session_destroy(m->session);
884 :
885 38815 : list_destroy(m->global_vars);
886 38815 : list_destroy(m->schema_path);
887 38815 : stack_pop_until(m, 0);
888 :
889 38815 : if (m->scanner.log) /* close and destroy stream */
890 0 : close_stream(m->scanner.log);
891 :
892 38815 : m->sa = NULL;
893 38815 : m->ta = NULL;
894 38815 : if (m->qc)
895 38815 : qc_destroy(m->qc);
896 38815 : m->qc = NULL;
897 38815 : }
898 :
899 : sql_type *
900 37677 : mvc_bind_type(mvc *sql, const char *name)
901 : {
902 37677 : sql_type *t = sql_trans_bind_type(sql->session->tr, NULL, name);
903 37677 : TRC_DEBUG(SQL_TRANS, "Bind type: %s\n", name);
904 37677 : return t;
905 : }
906 :
907 : sql_type *
908 1826 : schema_bind_type(mvc *sql, sql_schema *s, const char *name)
909 : {
910 1826 : sql_type *t = find_sql_type(sql->session->tr, s, name);
911 :
912 1826 : (void) sql;
913 1826 : if (!t)
914 : return NULL;
915 8 : TRC_DEBUG(SQL_TRANS, "Schema bind type: %s\n", name);
916 : return t;
917 : }
918 :
919 : sql_schema *
920 7626536 : mvc_bind_schema(mvc *m, const char *sname)
921 : {
922 7626536 : sql_trans *tr = m->session->tr;
923 7626536 : sql_schema *s;
924 :
925 7626536 : if (!tr)
926 : return NULL;
927 :
928 7626536 : s = find_sql_schema(tr, sname);
929 7625553 : if (!s)
930 : return NULL;
931 7556930 : TRC_DEBUG(SQL_TRANS, "Bind schema: %s\n", sname);
932 : return s;
933 : }
934 :
935 : sql_table *
936 4297299 : mvc_bind_table(mvc *m, sql_schema *s, const char *tname)
937 : {
938 4297299 : sql_table *t = find_sql_table(m->session->tr, s, tname);
939 :
940 4297377 : (void) m;
941 4297377 : if (!t)
942 : return NULL;
943 :
944 4020483 : TRC_DEBUG(SQL_TRANS, "Bind table: %s.%s\n", s->base.name, tname);
945 : return t;
946 : }
947 :
948 : sql_column *
949 3107630 : mvc_bind_column(mvc *m, sql_table *t, const char *cname)
950 : {
951 3107630 : sql_column *c;
952 :
953 3107630 : (void)m;
954 3107630 : c = find_sql_column(t, cname);
955 3107069 : if (!c)
956 : return NULL;
957 2903596 : TRC_DEBUG(SQL_TRANS, "Bind column: %s.%s\n", t->base.name, cname);
958 : return c;
959 : }
960 :
961 : static sql_column *
962 0 : first_column(sql_table *t)
963 : {
964 0 : node *n = ol_first_node(t->columns);
965 :
966 0 : if (n)
967 0 : return n->data;
968 : return NULL;
969 : }
970 :
971 : sql_column *
972 0 : mvc_first_column(mvc *m, sql_table *t)
973 : {
974 0 : sql_column *c = first_column(t);
975 :
976 0 : (void) m;
977 0 : if (!c)
978 : return NULL;
979 0 : TRC_DEBUG(SQL_TRANS, "First column: %s.%s\n", t->base.name, c->base.name);
980 : return c;
981 : }
982 :
983 : sql_key *
984 7308 : mvc_bind_key(mvc *m, sql_schema *s, const char *kname)
985 : {
986 7308 : sql_key *k = schema_find_key(m->session->tr, s, kname);
987 :
988 7308 : if (!k)
989 : return NULL;
990 43 : TRC_DEBUG(SQL_TRANS, "Bind key: %s.%s\n", s->base.name, kname);
991 : return k;
992 : }
993 :
994 : sql_idx *
995 19779 : mvc_bind_idx(mvc *m, sql_schema *s, const char *iname)
996 : {
997 19779 : sql_idx *i = schema_find_idx(m->session->tr, s, iname);
998 :
999 19777 : if (!i)
1000 : return NULL;
1001 12300 : TRC_DEBUG(SQL_TRANS, "Bind index: %s.%s\n", s->base.name, iname);
1002 : return i;
1003 : }
1004 :
1005 : static int
1006 915 : uniqueKey(sql_key *k)
1007 : {
1008 915 : return (k->type == pkey || k->type == ukey);
1009 : }
1010 :
1011 : sql_key *
1012 905 : mvc_bind_ukey(sql_table *t, list *colnames)
1013 : {
1014 905 : node *cn;
1015 905 : node *cur;
1016 905 : sql_key *res = NULL;
1017 905 : int len = list_length(colnames);
1018 :
1019 905 : if (ol_length(t->keys))
1020 917 : for (cur = ol_first_node(t->keys); cur; cur = cur->next) {
1021 915 : node *cc;
1022 915 : sql_key *k = cur->data;
1023 :
1024 915 : if (uniqueKey(k) && list_length(k->columns) == len) {
1025 905 : res = k;
1026 1835 : for (cc = k->columns->h, cn = colnames->h; cc && cn; cc = cc->next, cn = cn->next) {
1027 935 : sql_kc *c = cc->data;
1028 935 : char *n = cn->data;
1029 :
1030 935 : if (strcmp(c->c->base.name, n) != 0) {
1031 : res = NULL;
1032 : break;
1033 : }
1034 : }
1035 905 : if (res)
1036 : break;
1037 : }
1038 : }
1039 905 : return res;
1040 : }
1041 :
1042 : sql_trigger *
1043 950 : mvc_bind_trigger(mvc *m, sql_schema *s, const char *tname)
1044 : {
1045 950 : sql_trigger *t = schema_find_trigger(m->session->tr, s, tname);
1046 :
1047 950 : if (!t)
1048 : return NULL;
1049 173 : TRC_DEBUG(SQL_TRANS, "Bind trigger: %s.%s\n", s->base.name, tname);
1050 : return t;
1051 : }
1052 :
1053 : int
1054 906 : mvc_create_type(mvc *sql, sql_schema *s, const char *name, unsigned int digits, unsigned int scale, int radix, const char *impl)
1055 : {
1056 906 : TRC_DEBUG(SQL_TRANS, "Create type: %s\n", name);
1057 906 : return sql_trans_create_type(sql->session->tr, s, name, digits, scale, radix, impl);
1058 : }
1059 :
1060 : int
1061 3 : mvc_drop_type(mvc *m, sql_schema *s, sql_type *t, int drop_action)
1062 : {
1063 3 : TRC_DEBUG(SQL_TRANS, "Drop type: %s %s\n", s->base.name, t->base.name);
1064 3 : if (t)
1065 5 : return sql_trans_drop_type(m->session->tr, s, t->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1066 : return 0;
1067 : }
1068 :
1069 : int
1070 241080 : mvc_create_func(sql_func **f, mvc *m, allocator *sa, sql_schema *s, const char *name, list *args, list *res, sql_ftype type, sql_flang lang,
1071 : const char *mod, const char *impl, const char *query, bit varres, bit vararg, bit system, bit side_effect)
1072 : {
1073 241080 : int lres = LOG_OK;
1074 :
1075 241080 : TRC_DEBUG(SQL_TRANS, "Create function: %s\n", name);
1076 241080 : if (sa) {
1077 120339 : *f = create_sql_func(m->store, sa, name, args, res, type, lang, mod, impl, query, varres, vararg, system, side_effect);
1078 120339 : (*f)->s = s;
1079 : } else
1080 120741 : lres = sql_trans_create_func(f, m->session->tr, s, name, args, res, type, lang, mod, impl, query, varres, vararg, system, side_effect);
1081 241080 : return lres;
1082 : }
1083 :
1084 : int
1085 646 : mvc_drop_func(mvc *m, sql_schema *s, sql_func *f, int drop_action)
1086 : {
1087 646 : TRC_DEBUG(SQL_TRANS, "Drop function: %s %s\n", s->base.name, f->base.name);
1088 1250 : return sql_trans_drop_func(m->session->tr, s, f->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1089 : }
1090 :
1091 : int
1092 30 : mvc_drop_all_func(mvc *m, sql_schema *s, list *list_func, int drop_action)
1093 : {
1094 30 : TRC_DEBUG(SQL_TRANS, "Drop all functions: %s %s\n", s->base.name, ((sql_func *) list_func->h->data)->base.name);
1095 60 : return sql_trans_drop_all_func(m->session->tr, s, list_func, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1096 : }
1097 :
1098 : int
1099 1082 : mvc_create_schema(mvc *m, const char *name, sqlid auth_id, sqlid owner)
1100 : {
1101 1082 : TRC_DEBUG(SQL_TRANS, "Create schema: %s %d %d\n", name, auth_id, owner);
1102 1082 : return sql_trans_create_schema(m->session->tr, name, auth_id, owner, NULL);
1103 : }
1104 :
1105 : int
1106 159 : mvc_drop_schema(mvc *m, sql_schema * s, int drop_action)
1107 : {
1108 159 : TRC_DEBUG(SQL_TRANS, "Drop schema: %s\n", s->base.name);
1109 237 : return sql_trans_drop_schema(m->session->tr, s->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1110 : }
1111 :
1112 : int
1113 5969 : mvc_create_ukey(sql_key **kres, mvc *m, sql_table *t, const char *name, key_type kt, const char* check)
1114 : {
1115 5969 : int res = LOG_OK;
1116 :
1117 5969 : TRC_DEBUG(SQL_TRANS, "Create ukey: %s %u\n", t->base.name, (unsigned) kt);
1118 5969 : if (t->persistence == SQL_DECLARED_TABLE)
1119 5969 : *kres = create_sql_ukey(m->store, m->sa, t, name, kt, check);
1120 : else
1121 0 : res = sql_trans_create_ukey(kres, m->session->tr, t, name, kt, check);
1122 5969 : return res;
1123 : }
1124 :
1125 : int
1126 6891 : mvc_create_key_done(mvc *m, sql_key *k)
1127 : {
1128 6891 : int res = LOG_OK;
1129 :
1130 6891 : if (k->t->persistence == SQL_DECLARED_TABLE)
1131 6891 : key_create_done(m->session->tr, m->sa, k);
1132 : else
1133 0 : res = sql_trans_key_done(m->session->tr, k);
1134 6891 : return res;
1135 : }
1136 :
1137 : int
1138 941 : 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)
1139 : {
1140 941 : int res = LOG_OK;
1141 :
1142 941 : TRC_DEBUG(SQL_TRANS, "Create fkey: %s %u %p\n", t->base.name, (unsigned) kt, rkey);
1143 941 : if (t->persistence == SQL_DECLARED_TABLE)
1144 941 : *kres = create_sql_fkey(m->store, m->sa, t, name, kt, rkey, on_delete, on_update);
1145 : else
1146 0 : res = sql_trans_create_fkey(kres, m->session->tr, t, name, kt, rkey, on_delete, on_update);
1147 941 : return res;
1148 : }
1149 :
1150 : int
1151 6567 : mvc_create_kc(mvc *m, sql_key *k, sql_column *c)
1152 : {
1153 6567 : int res = LOG_OK;
1154 :
1155 6567 : if (k->t->persistence == SQL_DECLARED_TABLE)
1156 6567 : create_sql_kc(m->store, m->sa, k, c);
1157 : else
1158 0 : res = sql_trans_create_kc(m->session->tr, k, c);
1159 6567 : return res;
1160 : }
1161 :
1162 : int
1163 962 : mvc_create_fkc(mvc *m, sql_fkey *fk, sql_column *c)
1164 : {
1165 962 : int res = LOG_OK;
1166 962 : sql_key *k = (sql_key*)fk;
1167 :
1168 962 : if (k->t->persistence == SQL_DECLARED_TABLE)
1169 962 : create_sql_kc(m->store, m->sa, k, c);
1170 : else
1171 0 : res = sql_trans_create_fkc(m->session->tr, fk, c);
1172 962 : return res;
1173 : }
1174 :
1175 : int
1176 146 : mvc_drop_key(mvc *m, sql_schema *s, sql_key *k, int drop_action)
1177 : {
1178 146 : TRC_DEBUG(SQL_TRANS, "Drop key: %s %s\n", s->base.name, k->base.name);
1179 146 : if (k->t->persistence == SQL_DECLARED_TABLE) {
1180 0 : drop_sql_key(k->t, k->base.id, drop_action);
1181 0 : return 0;
1182 : } else
1183 291 : return sql_trans_drop_key(m->session->tr, s, k->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1184 : }
1185 :
1186 : int
1187 337 : mvc_create_idx(sql_idx **i, mvc *m, sql_table *t, const char *name, idx_type it)
1188 : {
1189 337 : int res = LOG_OK;
1190 :
1191 337 : TRC_DEBUG(SQL_TRANS, "Create index: %s %u\n", t->base.name, (unsigned) it);
1192 337 : if (t->persistence == SQL_DECLARED_TABLE)
1193 : /* declared tables should not end up in the catalog */
1194 337 : *i = create_sql_idx(m->store, m->sa, t, name, it);
1195 : else
1196 0 : res = sql_trans_create_idx(i, m->session->tr, t, name, it);
1197 337 : return res;
1198 : }
1199 :
1200 : int
1201 431 : mvc_create_ic(mvc *m, sql_idx *i, sql_column *c)
1202 : {
1203 431 : int res = LOG_OK;
1204 :
1205 431 : if (i->t->persistence == SQL_DECLARED_TABLE)
1206 : /* declared tables should not end up in the catalog */
1207 431 : create_sql_ic(m->store, m->sa, i, c);
1208 : else
1209 0 : res = sql_trans_create_ic(m->session->tr, i, c);
1210 431 : return res;
1211 : }
1212 :
1213 : int
1214 335 : mvc_create_idx_done(mvc *m, sql_idx *i)
1215 : {
1216 335 : int res = LOG_OK;
1217 :
1218 335 : (void) m;
1219 335 : (void) create_sql_idx_done(m->session->tr, i);
1220 335 : return res;
1221 : }
1222 :
1223 : int
1224 159 : mvc_drop_idx(mvc *m, sql_schema *s, sql_idx *i)
1225 : {
1226 159 : TRC_DEBUG(SQL_TRANS, "Drop index: %s %s\n", s->base.name, i->base.name);
1227 159 : if (i->t->persistence == SQL_DECLARED_TABLE) {
1228 : /* declared tables should not end up in the catalog */
1229 0 : drop_sql_idx(i->t, i->base.id);
1230 0 : return 0;
1231 : } else
1232 159 : return sql_trans_drop_idx(m->session->tr, s, i->base.id, DROP_RESTRICT);
1233 : }
1234 :
1235 : int
1236 343 : mvc_create_trigger(sql_trigger **tri, mvc *m, sql_table *t, const char *name, sht time, sht orientation, sht event, const char *old_name,
1237 : const char *new_name, const char *condition, const char *statement)
1238 : {
1239 343 : TRC_DEBUG(SQL_TRANS, "Create trigger: %s %d %d %d\n", t->base.name, time, orientation, event);
1240 343 : return sql_trans_create_trigger(tri, m->session->tr, t, name, time, orientation, event, old_name, new_name, condition, statement);
1241 : }
1242 :
1243 : int
1244 89 : mvc_drop_trigger(mvc *m, sql_schema *s, sql_trigger *tri)
1245 : {
1246 89 : TRC_DEBUG(SQL_TRANS, "Drop trigger: %s %s\n", s->base.name, tri->base.name);
1247 89 : return sql_trans_drop_trigger(m->session->tr, s, tri->base.id, DROP_RESTRICT);
1248 : }
1249 :
1250 : int
1251 11533 : 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)
1252 : {
1253 11533 : char *err = NULL;
1254 11533 : int res = LOG_OK;
1255 :
1256 11533 : assert(s);
1257 11533 : 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);
1258 11533 : if (persistence == SQL_DECLARED_TABLE) {
1259 10183 : *t = create_sql_table(m->store, m->sa, name, tt, system, persistence, commit_action, properties);
1260 10183 : (*t)->s = s;
1261 : } else {
1262 1350 : res = sql_trans_create_table(t, m->session->tr, s, name, NULL, tt, system, persistence, commit_action, sz, properties);
1263 1350 : if (res == LOG_OK && isPartitionedByExpressionTable(*t) && (err = bootstrap_partition_expression(m, *t, 1))) {
1264 0 : (void) sql_error(m, 02, "%s", err);
1265 0 : return -5;
1266 : }
1267 1350 : if (res == LOG_OK)
1268 1350 : res = sql_trans_set_partition_table(m->session->tr, *t);
1269 : }
1270 : return res;
1271 : }
1272 :
1273 : int
1274 22825 : mvc_create_view(sql_table **t, mvc *m, sql_schema *s, const char *name, int persistence, const char *sql, bit system)
1275 : {
1276 22825 : int res = LOG_OK;
1277 :
1278 22825 : TRC_DEBUG(SQL_TRANS, "Create view: %s %s %s\n", s->base.name, name, sql);
1279 22825 : if (persistence == SQL_DECLARED_TABLE) {
1280 22359 : *t = create_sql_table(m->store, m->sa, name, tt_view, system, persistence, 0, 0);
1281 22359 : (*t)->s = s;
1282 22359 : (*t)->query = sa_strdup(m->sa, sql);
1283 : } else {
1284 466 : res = sql_trans_create_table(t, m->session->tr, s, name, sql, tt_view, system, SQL_PERSIST, 0, 0, 0);
1285 : }
1286 22825 : return res;
1287 : }
1288 :
1289 : int
1290 101 : mvc_create_remote(sql_table **t, mvc *m, sql_schema *s, const char *name, int persistence, const char *loc)
1291 : {
1292 101 : int res = LOG_OK;
1293 :
1294 101 : TRC_DEBUG(SQL_TRANS, "Create remote: %s %s %s\n", s->base.name, name, loc);
1295 101 : if (persistence == SQL_DECLARED_TABLE) {
1296 101 : *t = create_sql_table(m->store, m->sa, name, tt_remote, 0, persistence, 0, 0);
1297 101 : (*t)->s = s;
1298 101 : (*t)->query = sa_strdup(m->sa, loc);
1299 : } else {
1300 0 : res = sql_trans_create_table(t, m->session->tr, s, name, loc, tt_remote, 0, SQL_REMOTE, 0, 0, 0);
1301 : }
1302 101 : return res;
1303 : }
1304 :
1305 : static str
1306 35 : remote_drop(mvc *m, sql_table *t)
1307 : {
1308 35 : sqlid id = t->base.id;
1309 35 : int log_res = 0;
1310 35 : sql_trans *tr = m->session->tr;
1311 35 : sqlstore *store = tr->store;
1312 35 : sql_schema *sys = find_sql_schema(tr, "sys");
1313 35 : sql_table *remote_user_info = find_sql_table(tr, sys, REMOTE_USER_INFO);
1314 35 : sql_column *remote_user_info_id = find_sql_column(remote_user_info, "table_id");
1315 35 : oid rid = store->table_api.column_find_row(tr, remote_user_info_id, &id, NULL);
1316 35 : if (is_oid_nil(rid)) {
1317 1 : TRC_WARNING(SQL_TRANS, "Drop table: %s %s no remote info\n", t->s->base.name, t->base.name);
1318 34 : } else if ((log_res = store->table_api.table_delete(tr, remote_user_info, rid)) != 0)
1319 0 : throw(SQL, "sql.drop_table", SQLSTATE(42000) "Drop table failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
1320 : return MAL_SUCCEED;
1321 : }
1322 :
1323 : str
1324 3993 : mvc_drop_table(mvc *m, sql_schema *s, sql_table *t, int drop_action)
1325 : {
1326 3993 : char *msg = NULL;
1327 3993 : TRC_DEBUG(SQL_TRANS, "Drop table: %s %s\n", s->base.name, t->base.name);
1328 :
1329 3993 : if (isRemote(t) && (msg = remote_drop(m, t)) != NULL)
1330 : return msg;
1331 :
1332 7512 : switch (sql_trans_drop_table(m->session->tr, s, t->base.name, drop_action ? DROP_CASCADE_START : DROP_RESTRICT)) {
1333 0 : case -1:
1334 0 : throw(SQL,"sql.mvc_drop_table",SQLSTATE(HY013) MAL_MALLOC_FAIL);
1335 0 : case -2:
1336 : case -3:
1337 0 : throw(SQL, "sql.mvc_drop_table", SQLSTATE(42000) "Transaction conflict while dropping table %s.%s", s->base.name, t->base.name);
1338 : default:
1339 : break;
1340 : }
1341 : return MAL_SUCCEED;
1342 : }
1343 :
1344 : BUN
1345 41826 : mvc_clear_table(mvc *m, sql_table *t)
1346 : {
1347 41826 : return sql_trans_clear_table(m->session->tr, t);
1348 : }
1349 :
1350 : int
1351 9827 : mvc_create_column_(sql_column **col, mvc *m, sql_table *t, const char *name, const char *type, unsigned int digits)
1352 : {
1353 9827 : sql_subtype tpe;
1354 :
1355 9827 : if (!sql_find_subtype(&tpe, type, digits, 0))
1356 : return -1;
1357 :
1358 9827 : return sql_trans_create_column(col, m->session->tr, t, name, &tpe);
1359 : }
1360 :
1361 : int
1362 256628 : mvc_create_column(sql_column **col, mvc *m, sql_table *t, const char *name, sql_subtype *tpe)
1363 : {
1364 256628 : int res = LOG_OK;
1365 :
1366 256628 : TRC_DEBUG(SQL_TRANS, "Create column: %s %s %s\n", t->base.name, name, tpe->type->base.name);
1367 256628 : if (t->persistence == SQL_DECLARED_TABLE)
1368 : /* declared tables should not end up in the catalog */
1369 256628 : *col = create_sql_column(m->store, m->sa, t, name, tpe);
1370 : else
1371 0 : res = sql_trans_create_column(col, m->session->tr, t, name, tpe);
1372 256628 : return res;
1373 : }
1374 :
1375 : int
1376 136 : mvc_drop_column(mvc *m, sql_table *t, sql_column *col, int drop_action)
1377 : {
1378 136 : TRC_DEBUG(SQL_TRANS, "Drop column: %s %s\n", t->base.name, col->base.name);
1379 136 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1380 68 : drop_sql_column(t, col->base.id, drop_action);
1381 68 : return 0;
1382 : } else
1383 128 : return sql_trans_drop_column(m->session->tr, t, col->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1384 : }
1385 :
1386 : int
1387 370199 : mvc_create_dependency(mvc *m, sql_base *b, sqlid depend_id, sql_dependency depend_type)
1388 : {
1389 370199 : int res = LOG_OK;
1390 :
1391 370199 : TRC_DEBUG(SQL_TRANS, "Create dependency: %d %d %d\n", b->id, depend_id, (int) depend_type);
1392 370199 : if ( (b->id != depend_id) || (depend_type == BEDROPPED_DEPENDENCY) ) {
1393 370198 : if (!b->new)
1394 222629 : res = sql_trans_add_dependency(m->session->tr, b->id, ddl);
1395 222629 : if (res == LOG_OK)
1396 370198 : res = sql_trans_create_dependency(m->session->tr, b->id, depend_id, depend_type);
1397 : }
1398 370199 : return res;
1399 : }
1400 :
1401 : int
1402 144421 : mvc_create_dependencies(mvc *m, list *blist, sqlid depend_id, sql_dependency dep_type)
1403 : {
1404 144421 : int res = LOG_OK;
1405 :
1406 144421 : TRC_DEBUG(SQL_TRANS, "Create dependencies on '%d' of type: %d\n", depend_id, (int) dep_type);
1407 144421 : if (!list_empty(blist)) {
1408 383736 : for (node *n = blist->h ; n && res == LOG_OK ; n = n->next) {
1409 356655 : sql_base *b = n->data;
1410 356655 : if (!b->new) /* only add old objects to the transaction dependency list */
1411 222585 : res = sql_trans_add_dependency(m->session->tr, b->id, ddl);
1412 356655 : if (res == LOG_OK)
1413 356655 : res = mvc_create_dependency(m, b, depend_id, dep_type);
1414 : }
1415 : }
1416 144421 : return res;
1417 : }
1418 :
1419 : int
1420 4668 : mvc_check_dependency(mvc *m, sqlid id, sql_dependency type, list *ignore_ids)
1421 : {
1422 4668 : list *dep_list = NULL;
1423 :
1424 4668 : TRC_DEBUG(SQL_TRANS, "Check dependency on: %d\n", id);
1425 4668 : switch (type) {
1426 107 : case OWNER_DEPENDENCY:
1427 107 : dep_list = sql_trans_owner_schema_dependencies(m->session->tr, id);
1428 107 : break;
1429 17 : case SCHEMA_DEPENDENCY:
1430 17 : dep_list = sql_trans_schema_user_dependencies(m->session->tr, id);
1431 17 : if (!dep_list)
1432 17 : dep_list = sql_trans_get_dependents(m->session->tr, id, SCHEMA_DEPENDENCY, NULL);
1433 : break;
1434 3309 : case TABLE_DEPENDENCY:
1435 3309 : dep_list = sql_trans_get_dependents(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1436 3309 : break;
1437 311 : case VIEW_DEPENDENCY:
1438 311 : dep_list = sql_trans_get_dependents(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1439 311 : break;
1440 650 : case FUNC_DEPENDENCY:
1441 : case PROC_DEPENDENCY:
1442 650 : dep_list = sql_trans_get_dependents(m->session->tr, id, FUNC_DEPENDENCY, ignore_ids);
1443 650 : break;
1444 274 : default:
1445 274 : dep_list = sql_trans_get_dependents(m->session->tr, id, COLUMN_DEPENDENCY, NULL);
1446 : }
1447 :
1448 4668 : if (!dep_list)
1449 : return DEPENDENCY_CHECK_ERROR;
1450 :
1451 4668 : if (list_length(dep_list) >= 2) {
1452 49 : list_destroy(dep_list);
1453 49 : return HAS_DEPENDENCY;
1454 : }
1455 :
1456 4619 : list_destroy(dep_list);
1457 4619 : return NO_DEPENDENCY;
1458 : }
1459 :
1460 : int
1461 17190 : mvc_null(mvc *m, sql_column *col, int isnull)
1462 : {
1463 17190 : TRC_DEBUG(SQL_TRANS, "Null: %s %d\n", col->base.name, isnull);
1464 17190 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1465 17093 : col->null = isnull;
1466 17093 : return 0;
1467 : }
1468 97 : return sql_trans_alter_null(m->session->tr, col, isnull);
1469 : }
1470 :
1471 : int
1472 1431 : mvc_default(mvc *m, sql_column *col, char *val)
1473 : {
1474 1431 : TRC_DEBUG(SQL_TRANS, "Default: %s %s\n", col->base.name, val);
1475 1431 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1476 1408 : col->def = val?sa_strdup(m->sa, val):NULL;
1477 1408 : return 0;
1478 : } else {
1479 23 : return sql_trans_alter_default(m->session->tr, col, val);
1480 : }
1481 : }
1482 :
1483 : int
1484 6 : mvc_drop_default(mvc *m, sql_column *col)
1485 : {
1486 6 : TRC_DEBUG(SQL_TRANS, "Drop default: %s\n", col->base.name);
1487 6 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1488 6 : col->def = NULL;
1489 6 : return 0;
1490 : } else {
1491 0 : return sql_trans_alter_default(m->session->tr, col, NULL);
1492 : }
1493 : }
1494 :
1495 : int
1496 0 : mvc_storage(mvc *m, sql_column *col, char *storage)
1497 : {
1498 0 : TRC_DEBUG(SQL_TRANS, "Storage: %s %s\n", col->base.name, storage);
1499 0 : if (col->t->persistence == SQL_DECLARED_TABLE) {
1500 0 : col->storage_type = storage?sa_strdup(m->sa, storage):NULL;
1501 0 : return 0;
1502 : } else {
1503 0 : return sql_trans_alter_storage(m->session->tr, col, storage);
1504 : }
1505 : }
1506 :
1507 : int
1508 2309 : mvc_access(mvc *m, sql_table *t, sht access)
1509 : {
1510 2309 : TRC_DEBUG(SQL_TRANS, "Access: %s %d\n", t->base.name, access);
1511 2309 : if (t->persistence == SQL_DECLARED_TABLE) {
1512 0 : t->access = access;
1513 0 : return 0;
1514 : }
1515 2309 : return sql_trans_alter_access(m->session->tr, t, access);
1516 : }
1517 :
1518 : int
1519 21598 : mvc_is_sorted(mvc *m, sql_column *col)
1520 : {
1521 21598 : TRC_DEBUG(SQL_TRANS, "Is sorted: %s\n", col->base.name);
1522 21598 : return sql_trans_is_sorted(m->session->tr, col);
1523 : }
1524 :
1525 : int
1526 7814 : mvc_is_unique(mvc *m, sql_column *col)
1527 : {
1528 7814 : TRC_DEBUG(SQL_TRANS, "Is unique: %s\n", col->base.name);
1529 7814 : return sql_trans_is_unique(m->session->tr, col);
1530 : }
1531 :
1532 : int
1533 2048 : mvc_is_duplicate_eliminated(mvc *m, sql_column *col)
1534 : {
1535 2048 : TRC_DEBUG(SQL_TRANS, "Is duplicate eliminated: %s\n", col->base.name);
1536 2048 : return sql_trans_is_duplicate_eliminated(m->session->tr, col);
1537 : }
1538 :
1539 : int
1540 4053813 : mvc_col_stats(mvc *m, sql_column *col, bool *nonil, bool *unique, double *unique_est, ValPtr min, ValPtr max)
1541 : {
1542 4053813 : TRC_DEBUG(SQL_TRANS, "Retrieving column stats for: %s\n", col->base.name);
1543 4053813 : return sql_trans_col_stats(m->session->tr, col, nonil, unique, unique_est, min, max);
1544 : }
1545 :
1546 : int
1547 256208 : mvc_copy_column(mvc *m, sql_table *t, sql_column *c, sql_column **cres)
1548 : {
1549 256208 : return sql_trans_copy_column(m->session->tr, t, c, cres);
1550 : }
1551 :
1552 : int
1553 6868 : mvc_copy_key(mvc *m, sql_table *t, sql_key *k, sql_key **kres)
1554 : {
1555 6868 : return sql_trans_copy_key(m->session->tr, t, k, kres);
1556 : }
1557 :
1558 : int
1559 7165 : mvc_copy_idx(mvc *m, sql_table *t, sql_idx *i, sql_idx **ires)
1560 : {
1561 7165 : return sql_trans_copy_idx(m->session->tr, t, i, ires);
1562 : }
1563 :
1564 : int
1565 0 : mvc_copy_trigger(mvc *m, sql_table *t, sql_trigger *tr, sql_trigger **tres)
1566 : {
1567 0 : return sql_trans_copy_trigger(m->session->tr, t, tr, tres);
1568 : }
1569 :
1570 : sql_rel *
1571 708625 : sql_processrelation(mvc *sql, sql_rel *rel, int profile, int instantiate, int value_based_opt, int storage_based_opt)
1572 : {
1573 708625 : int emode = sql->emode;
1574 708625 : if (!instantiate)
1575 143407 : sql->emode = m_deps;
1576 708625 : if (rel)
1577 708625 : rel = rel_unnest(sql, rel);
1578 708600 : sql->emode = emode;
1579 708600 : if (rel)
1580 708584 : rel = rel_optimizer(sql, rel, profile, instantiate, value_based_opt, storage_based_opt);
1581 708616 : return rel;
1582 : }
1583 :
1584 : static inline int dlist_cmp(mvc *sql, dlist *l1, dlist *l2);
1585 :
1586 : static inline int
1587 385 : dnode_cmp(mvc *sql, dnode *d1, dnode *d2)
1588 : {
1589 385 : if (d1 == d2)
1590 : return 0;
1591 :
1592 385 : if (!d1 || !d2)
1593 : return -1;
1594 :
1595 385 : if (d1->type == d2->type) {
1596 385 : switch (d1->type) {
1597 35 : case type_int:
1598 35 : return (d1->data.i_val - d2->data.i_val);
1599 0 : case type_lng: {
1600 0 : lng c = d1->data.l_val - d2->data.l_val;
1601 0 : assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
1602 0 : return (int) c;
1603 : }
1604 202 : case type_string:
1605 202 : if (d1->data.sval == d2->data.sval)
1606 : return 0;
1607 202 : if (!d1->data.sval || !d2->data.sval)
1608 : return -1;
1609 202 : return strcmp(d1->data.sval, d2->data.sval);
1610 63 : case type_list:
1611 63 : return dlist_cmp(sql, d1->data.lval, d2->data.lval);
1612 85 : case type_symbol:
1613 85 : return symbol_cmp(sql, d1->data.sym, d2->data.sym);
1614 0 : case type_type:
1615 0 : return subtype_cmp(&d1->data.typeval, &d2->data.typeval);
1616 : default:
1617 0 : assert(0);
1618 : }
1619 : }
1620 : return -1;
1621 : }
1622 :
1623 : static inline int
1624 268 : dlist_cmp(mvc *sql, dlist *l1, dlist *l2)
1625 : {
1626 268 : int res = 0;
1627 268 : dnode *d1, *d2;
1628 :
1629 268 : if (l1 == l2)
1630 : return 0;
1631 :
1632 268 : if (!l1 || !l2 || dlist_length(l1) != dlist_length(l2))
1633 20 : return -1;
1634 :
1635 633 : for (d1 = l1->h, d2 = l2->h; !res && d1; d1 = d1->next, d2 = d2->next) {
1636 385 : res = dnode_cmp(sql, d1, d2);
1637 : }
1638 : return res;
1639 : }
1640 :
1641 : static inline int
1642 30 : AtomNodeCmp(AtomNode *a1, AtomNode *a2)
1643 : {
1644 30 : if (a1 == a2)
1645 : return 0;
1646 30 : if (!a1 || !a2)
1647 : return -1;
1648 30 : if (a1->a && a2->a)
1649 30 : return atom_cmp(a1->a, a2->a);
1650 : return -1;
1651 : }
1652 :
1653 : static inline int
1654 0 : SelectNodeCmp(mvc *sql, SelectNode *s1, SelectNode *s2)
1655 : {
1656 0 : if (s1 == s2)
1657 : return 0;
1658 0 : if (!s1 || !s2)
1659 : return -1;
1660 :
1661 0 : if (symbol_cmp(sql, s1->limit, s2->limit) == 0 &&
1662 0 : symbol_cmp(sql, s1->offset, s2->offset) == 0 &&
1663 0 : symbol_cmp(sql, s1->sample, s2->sample) == 0 &&
1664 0 : symbol_cmp(sql, s1->seed, s2->seed) == 0 &&
1665 0 : s1->distinct == s2->distinct &&
1666 0 : s1->lateral == s2->lateral &&
1667 0 : symbol_cmp(sql, s1->name, s2->name) == 0 &&
1668 0 : symbol_cmp(sql, s1->orderby, s2->orderby) == 0 &&
1669 0 : symbol_cmp(sql, s1->having, s2->having) == 0 &&
1670 0 : symbol_cmp(sql, s1->groupby, s2->groupby) == 0 &&
1671 0 : symbol_cmp(sql, s1->where, s2->where) == 0 &&
1672 0 : symbol_cmp(sql, s1->from, s2->from) == 0 &&
1673 0 : symbol_cmp(sql, s1->window, s2->window) == 0 &&
1674 0 : dlist_cmp(sql, s1->selection, s2->selection) == 0)
1675 : return 0;
1676 : return -1;
1677 : }
1678 :
1679 : static inline int
1680 239 : _symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
1681 : {
1682 239 : if (s1 == s2)
1683 : return 0;
1684 239 : if (!s1 || !s2)
1685 : return -1;
1686 239 : if (s1->token != s2->token || s1->type != s2->type)
1687 : return -1;
1688 235 : switch (s1->type) {
1689 0 : case type_int:
1690 0 : return (s1->data.i_val - s2->data.i_val);
1691 0 : case type_lng: {
1692 0 : lng c = s1->data.l_val - s2->data.l_val;
1693 0 : assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
1694 0 : return (int) c;
1695 : }
1696 0 : case type_string:
1697 0 : if (s1->data.sval == s2->data.sval)
1698 : return 0;
1699 0 : if (!s1->data.sval || !s2->data.sval)
1700 : return -1;
1701 0 : return strcmp(s1->data.sval, s2->data.sval);
1702 205 : case type_list: {
1703 205 : return dlist_cmp(sql, s1->data.lval, s2->data.lval);
1704 : }
1705 0 : case type_type:
1706 0 : return subtype_cmp(&s1->data.typeval, &s2->data.typeval);
1707 30 : case type_symbol:
1708 30 : if (s1->token == SQL_SELECT) {
1709 0 : if (s2->token != SQL_SELECT)
1710 : return -1;
1711 0 : return SelectNodeCmp(sql, (SelectNode *) s1, (SelectNode *) s2);
1712 30 : } else if (s1->token == SQL_ATOM) {
1713 30 : if (s2->token != SQL_ATOM)
1714 : return -1;
1715 30 : return AtomNodeCmp((AtomNode *) s1, (AtomNode *) s2);
1716 : } else {
1717 0 : return symbol_cmp(sql, s1->data.sym, s2->data.sym);
1718 : }
1719 : default:
1720 0 : assert(0);
1721 : }
1722 : return 0; /* never reached, just to pacify compilers */
1723 : }
1724 :
1725 : int
1726 239 : symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
1727 : {
1728 239 : return _symbol_cmp(sql, s1, s2);
1729 : }
|