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