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