1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/* multi version catalog */
10
11#include "monetdb_config.h"
12#include "gdk.h"
13
14#include "sql_mvc.h"
15#include "sql_qc.h"
16#include "sql_types.h"
17#include "sql_env.h"
18#include "sql_semantic.h"
19#include "sql_partition.h"
20#include "sql_privileges.h"
21#include "sql_querytype.h"
22#include "rel_rel.h"
23#include "rel_exp.h"
24#include "rel_semantic.h"
25#include "rel_unnest.h"
26#include "rel_optimizer.h"
27#include "gdk_logger.h"
28#include "wlc.h"
29
30#include "mal_authorize.h"
31
32static int mvc_debug = 0;
33
34static void
35sql_create_comments(mvc *m, sql_schema *s)
36{
37 sql_table *t;
38 sql_column *c;
39 sql_key *k;
40
41 t = mvc_create_table(m, s, "comments", tt_table, 1, SQL_PERSIST, 0, -1, 0);
42 c = mvc_create_column_(m, t, "id", "int", 32);
43 k = sql_trans_create_ukey(m->session->tr, t, "comments_id_pkey", pkey);
44 k = sql_trans_create_kc(m->session->tr, k, c);
45 k = sql_trans_key_done(m->session->tr, k);
46 sql_trans_create_dependency(m->session->tr, c->base.id, k->idx->base.id, INDEX_DEPENDENCY);
47 c = mvc_create_column_(m, t, "remark", "varchar", 65000);
48 sql_trans_alter_null(m->session->tr, c, 0);
49}
50
51sql_table *
52mvc_init_create_view(mvc *m, sql_schema *s, const char *name, const char *query)
53{
54 sql_table *t = mvc_create_view(m, s, name, SQL_PERSIST, query, 1);
55
56 if (t) {
57 char *buf;
58 sql_rel *r = NULL;
59 sql_allocator *old_sa = m->sa;
60
61 if (!(m->sa = sa_create())) {
62 t = NULL;
63 (void) sql_error(m, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
64 goto bailout;
65 }
66
67 if (!(buf = sa_strdup(m->sa, t->query))) {
68 t = NULL;
69 (void) sql_error(m, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
70 goto bailout;
71 }
72
73 r = rel_parse(m, s, buf, m_deps);
74 if (r)
75 r = rel_unnest(m, r);
76 if (r)
77 r = rel_optimizer(m, r, 0);
78 if (r) {
79 list *id_l = rel_dependencies(m, r);
80 mvc_create_dependencies(m, id_l, t->base.id, VIEW_DEPENDENCY);
81 }
82bailout:
83 if (m->sa)
84 sa_destroy(m->sa);
85 m->sa = old_sa;
86 }
87 return t;
88}
89
90#define MVC_INIT_DROP_TABLE(SQLID, TNAME) \
91 t = mvc_bind_table(m, s, TNAME); \
92 SQLID = t->base.id; \
93 if((output = mvc_drop_table(m, s, t, 0)) != MAL_SUCCEED) { \
94 mvc_destroy(m); \
95 fprintf(stderr, "!mvc_init: %s\n", output); \
96 freeException(output); \
97 return -1; \
98 }
99
100int
101mvc_init(int debug, store_type store, int ro, int su, backend_stack stk)
102{
103 int first = 0;
104 sql_schema *s;
105 sql_table *t;
106 sqlid tid = 0, ntid, cid = 0, ncid;
107 mvc *m;
108 str msg;
109
110 mvc_debug = debug&4;
111 if (mvc_debug) {
112 fprintf(stderr, "#mvc_init\n");
113 }
114 keyword_init();
115 if(scanner_init_keywords() != 0) {
116 fprintf(stderr, "!mvc_init: malloc failure\n");
117 return -1;
118 }
119
120 if ((first = store_init(debug, store, ro, su, stk)) < 0) {
121 fprintf(stderr, "!mvc_init: unable to create system tables\n");
122 return -1;
123 }
124
125 m = mvc_create(0, stk, 0, NULL, NULL);
126 if (!m) {
127 fprintf(stderr, "!mvc_init: malloc failure\n");
128 return -1;
129 }
130
131 m->sa = sa_create();
132 if (!m->sa) {
133 mvc_destroy(m);
134 fprintf(stderr, "!mvc_init: malloc failure\n");
135 return -1;
136 }
137
138 /* disable caching */
139 m->caching = 0;
140 /* disable size header */
141 m->sizeheader = false;
142
143 if (first || catalog_version) {
144 if (mvc_trans(m) < 0) {
145 mvc_destroy(m);
146 fprintf(stderr, "!mvc_init: failed to start transaction\n");
147 return -1;
148 }
149
150 s = m->session->schema = mvc_bind_schema(m, "sys");
151 assert(m->session->schema != NULL);
152
153 if (!first) {
154 str output;
155 MVC_INIT_DROP_TABLE(tid, "tables")
156 MVC_INIT_DROP_TABLE(cid, "columns")
157 }
158
159 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\";");
160 if (!t) {
161 mvc_destroy(m);
162 fprintf(stderr, "!mvc_init: failed to create 'tables' view\n");
163 return -1;
164 }
165
166 ntid = t->base.id;
167 mvc_create_column_(m, t, "id", "int", 32);
168 mvc_create_column_(m, t, "name", "varchar", 1024);
169 mvc_create_column_(m, t, "schema_id", "int", 32);
170 mvc_create_column_(m, t, "query", "varchar", 1 << 20);
171 mvc_create_column_(m, t, "type", "smallint", 16);
172 mvc_create_column_(m, t, "system", "boolean", 1);
173 mvc_create_column_(m, t, "commit_action", "smallint", 16);
174 mvc_create_column_(m, t, "access", "smallint", 16);
175 mvc_create_column_(m, t, "temporary", "smallint", 16);
176
177 if (!first) {
178 int pub = ROLE_PUBLIC;
179 int p = PRIV_SELECT;
180 int zero = 0;
181 sql_table *privs = find_sql_table(s, "privileges");
182 sql_table *deps = find_sql_table(s, "dependencies");
183 sql_column *depids = find_sql_column(deps, "id");
184 oid rid;
185 rids *rs;
186
187 table_funcs.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
188 rs = table_funcs.rids_select(m->session->tr, depids, &tid, &tid, NULL);
189 while ((rid = table_funcs.rids_next(rs)), !is_oid_nil(rid)) {
190 table_funcs.column_update_value(m->session->tr, depids, rid, &ntid);
191 }
192 table_funcs.rids_destroy(rs);
193 }
194
195 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;");
196 if (!t) {
197 mvc_destroy(m);
198 fprintf(stderr, "!mvc_init: failed to create 'columns' view\n");
199 return -1;
200 }
201 ncid = t->base.id;
202 mvc_create_column_(m, t, "id", "int", 32);
203 mvc_create_column_(m, t, "name", "varchar", 1024);
204 mvc_create_column_(m, t, "type", "varchar", 1024);
205 mvc_create_column_(m, t, "type_digits", "int", 32);
206 mvc_create_column_(m, t, "type_scale", "int", 32);
207 mvc_create_column_(m, t, "table_id", "int", 32);
208 mvc_create_column_(m, t, "default", "varchar", STORAGE_MAX_VALUE_LENGTH);
209 mvc_create_column_(m, t, "null", "boolean", 1);
210 mvc_create_column_(m, t, "number", "int", 32);
211 mvc_create_column_(m, t, "storage", "varchar", 2048);
212
213 if (!first) {
214 int pub = ROLE_PUBLIC;
215 int p = PRIV_SELECT;
216 int zero = 0;
217 sql_table *privs = find_sql_table(s, "privileges");
218 sql_table *deps = find_sql_table(s, "dependencies");
219 sql_column *depids = find_sql_column(deps, "id");
220 oid rid;
221 rids *rs;
222
223 table_funcs.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
224 rs = table_funcs.rids_select(m->session->tr, depids, &cid, &cid, NULL);
225 while ((rid = table_funcs.rids_next(rs)), !is_oid_nil(rid)) {
226 table_funcs.column_update_value(m->session->tr, depids, rid, &ncid);
227 }
228 table_funcs.rids_destroy(rs);
229 } else {
230 sql_create_env(m, s);
231 sql_create_comments(m, s);
232 sql_create_privileges(m, s);
233 }
234
235 s = m->session->schema = mvc_bind_schema(m, "tmp");
236 assert(m->session->schema != NULL);
237
238 if ((msg = mvc_commit(m, 0, NULL, false)) != MAL_SUCCEED) {
239 fprintf(stderr, "!mvc_init: unable to commit system tables: %s\n", (msg + 6));
240 freeException(msg);
241 return -1;
242 }
243 }
244
245 if(mvc_trans(m) < 0) {
246 mvc_destroy(m);
247 fprintf(stderr, "!mvc_init: failed to start transaction\n");
248 return -1;
249 }
250
251 //as the sql_parser is not yet initialized in the storage, we determine the sql type of the sql_parts here
252 for (node *n = m->session->tr->schemas.set->h; n; n = n->next) {
253 sql_schema *ss = (sql_schema*) n->data;
254 if(ss->tables.set) {
255 for (node *nn = ss->tables.set->h; nn; nn = nn->next) {
256 sql_table *tt = (sql_table*) nn->data;
257 if(isPartitionedByColumnTable(tt) || isPartitionedByExpressionTable(tt)) {
258 char *err;
259 if((err = initialize_sql_parts(m, tt)) != NULL) {
260 fprintf(stderr, "!mvc_init: unable to start partitioned table: %s.%s: %s\n",
261 ss->base.name, tt->base.name, err);
262 freeException(err);
263 return -1;
264 }
265 }
266 }
267 }
268 }
269
270 if ((msg = mvc_commit(m, 0, NULL, false)) != MAL_SUCCEED) {
271 fprintf(stderr, "!mvc_init: unable to commit system tables: %s\n", (msg + 6));
272 freeException(msg);
273 return -1;
274 }
275
276 mvc_destroy(m);
277 return first;
278}
279
280void
281mvc_exit(void)
282{
283 if (mvc_debug)
284 fprintf(stderr, "#mvc_exit\n");
285
286 store_exit();
287 keyword_exit();
288}
289
290void
291mvc_logmanager(void)
292{
293 store_manager();
294}
295
296void
297mvc_idlemanager(void)
298{
299 idle_manager();
300}
301
302int
303mvc_status(mvc *m)
304{
305 int res = m->session->status;
306
307 return res;
308}
309
310int
311mvc_error_retry(mvc *m)
312{
313 int res = m->session->status;
314
315 if (!res || res == -ERR_AMBIGUOUS || res == -ERR_GROUPBY)
316 return 0;
317 return res;
318}
319
320int
321mvc_type(mvc *m)
322{
323 int res = m->type;
324
325 m->type = Q_PARSE;
326 return res;
327}
328
329int
330mvc_debug_on(mvc *m, int flg)
331{
332
333 if (m->debug & flg)
334 return 1;
335
336 return 0;
337}
338
339void
340mvc_cancel_session(mvc *m)
341{
342 store_lock();
343 sql_trans_end(m->session);
344 store_unlock();
345}
346
347int
348mvc_trans(mvc *m)
349{
350 int schema_changed = 0, err = m->session->status;
351 assert(!m->session->tr->active); /* can only start a new transaction */
352
353 store_lock();
354 if (GDKverbose >= 1)
355 fprintf(stderr, "#%s: starting transaction\n",
356 MT_thread_getname());
357 schema_changed = sql_trans_begin(m->session);
358 if (m->qc && (schema_changed || m->qc->nr > m->cache || err)){
359 if (schema_changed || err) {
360 int seqnr = m->qc->id;
361 if (m->qc)
362 qc_destroy(m->qc);
363 m->qc = qc_create(m->clientid, seqnr);
364 if (!m->qc) {
365 sql_trans_end(m->session);
366 store_unlock();
367 return -1;
368 }
369 } else { /* clean all but the prepared statements */
370 qc_clean(m->qc);
371 }
372 }
373 store_unlock();
374 return 0;
375}
376
377static sql_trans *
378sql_trans_deref( sql_trans *tr )
379{
380 node *n, *m, *o;
381
382 for ( n = tr->schemas.set->h; n; n = n->next) {
383 sql_schema *s = n->data;
384
385 if (s->tables.set)
386 for ( m = s->tables.set->h; m; m = m->next) {
387 sql_table *t = m->data;
388
389 if (t->po) {
390 sql_table *p = t->po;
391
392 if (t->base.rtime < p->base.rtime)
393 t->base.rtime = p->base.rtime;
394 if (t->base.wtime < p->base.wtime)
395 t->base.wtime = p->base.wtime;
396 t->po = p->po;
397 p->po = NULL; /* we used its reference */
398 table_destroy(p);
399 }
400
401 if (t->columns.set) {
402 for ( o = t->columns.set->h; o; o = o->next) {
403 sql_column *c = o->data;
404
405 if (c->po) {
406 sql_column *p = c->po;
407
408 if (c->base.rtime < p->base.rtime)
409 c->base.rtime = p->base.rtime;
410 if (c->base.wtime < p->base.wtime)
411 c->base.wtime = p->base.wtime;
412 c->po = p->po;
413 p->po = NULL; /* we used its reference */
414 column_destroy(p);
415 }
416 }
417 if(isPartitionedByColumnTable(t)) {
418 t->part.pcol = t->po->part.pcol;
419 } else if(isPartitionedByExpressionTable(t)) {
420 t->part.pexp = t->po->part.pexp;
421 }
422 }
423 if (t->idxs.set)
424 for ( o = t->idxs.set->h; o; o = o->next) {
425 sql_idx *i = o->data;
426
427 if (i->po) {
428 sql_idx *p = i->po;
429
430 if (i->base.rtime < p->base.rtime)
431 i->base.rtime = p->base.rtime;
432 if (i->base.wtime < p->base.wtime)
433 i->base.wtime = p->base.wtime;
434 i->po = p->po;
435 p->po = NULL; /* we used its reference */
436 idx_destroy(p);
437 }
438 }
439 }
440 }
441 return tr->parent;
442}
443
444str
445mvc_commit(mvc *m, int chain, const char *name, bool enabling_auto_commit)
446{
447 sql_trans *cur, *tr = m->session->tr, *ctr;
448 int ok = SQL_OK;//, wait = 0;
449 str msg, other;
450 char operation[BUFSIZ];
451
452 assert(tr);
453 assert(m->session->tr->active); /* only commit an active transaction */
454
455 if (mvc_debug)
456 fprintf(stderr, "#mvc_commit %s\n", (name) ? name : "");
457
458 if(enabling_auto_commit)
459 snprintf(operation, BUFSIZ, "Commit failed while enabling auto_commit: ");
460 else if(name)
461 snprintf(operation, BUFSIZ, "SAVEPOINT: (%s)", name);
462 else
463 snprintf(operation, BUFSIZ, "COMMIT:");
464
465 if (m->session->status < 0) {
466 msg = createException(SQL, "sql.commit", SQLSTATE(40000) "%s transaction is aborted, will ROLLBACK instead", operation);
467 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
468 freeException(other);
469 return msg;
470 }
471
472 /* savepoint then simply make a copy of the current transaction */
473 if (name && name[0] != '\0') {
474 sql_trans *tr = m->session->tr;
475 if (mvc_debug)
476 fprintf(stderr, "#mvc_savepoint\n");
477 store_lock();
478 m->session->tr = sql_trans_create(m->session->stk, tr, name, true);
479 if(!m->session->tr) {
480 store_unlock();
481 msg = createException(SQL, "sql.commit", SQLSTATE(HY001) "%s allocation failure while committing the transaction, will ROLLBACK instead", operation);
482 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
483 freeException(other);
484 return msg;
485 }
486 msg = WLCcommit(m->clientid);
487 store_unlock();
488 if(msg != MAL_SUCCEED) {
489 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
490 freeException(other);
491 return msg;
492 }
493 m->type = Q_TRANS;
494 if (m->qc) /* clean query cache, protect against concurrent access on the hash tables (when functions already exists, concurrent mal will
495build up the hash (not copied in the trans dup)) */
496 qc_clean(m->qc);
497 m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name);
498 if (mvc_debug)
499 fprintf(stderr, "#mvc_commit %s done\n", name);
500 if (GDKverbose >= 1)
501 fprintf(stderr, "#%s: savepoint commit %s done\n",
502 MT_thread_getname(), name);
503 return msg;
504 }
505
506 /* first release all intermediate savepoints */
507 ctr = cur = tr;
508 tr = tr->parent;
509 if (tr->parent) {
510 store_lock();
511 while (ctr->parent->parent != NULL && ok == SQL_OK) {
512 /* first free references to tr objects, ie
513 * c->po = c->po->po etc
514 */
515 ctr = sql_trans_deref(ctr);
516 }
517 while (tr->parent != NULL && ok == SQL_OK)
518 tr = sql_trans_destroy(tr, true);
519 store_unlock();
520 }
521 cur -> parent = tr;
522 tr = cur;
523
524 store_lock();
525 /* if there is nothing to commit reuse the current transaction */
526 if (tr->wtime == 0) {
527 if (!chain)
528 sql_trans_end(m->session);
529 m->type = Q_TRANS;
530 msg = WLCcommit(m->clientid);
531 store_unlock();
532 if(msg != MAL_SUCCEED) {
533 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
534 freeException(other);
535 return msg;
536 }
537 if (mvc_debug)
538 fprintf(stderr, "#mvc_commit done\n");
539 if (GDKverbose >= 1)
540 fprintf(stderr, "#%s: commit done (no changes)%s%.200s\n",
541 MT_thread_getname(),
542 GDKverbose >= 2 && m->query ? ", query: " : "",
543 GDKverbose >= 2 && m->query ? m->query : "");
544 return msg;
545 }
546
547 /*
548 while (tr->schema_updates && ATOMIC_GET(&store_nr_active) > 1) {
549 store_unlock();
550 MT_sleep_ms(100);
551 wait += 100;
552 if (wait > 1000) {
553 (void)sql_error(m, 010, SQLSTATE(40000) "COMMIT: transaction is aborted because of DDL concurrency conflicts, will ROLLBACK instead");
554 mvc_rollback(m, chain, name, false);
555 return -1;
556 }
557 store_lock();
558 }
559 * */
560 /* validation phase */
561 int valide = sql_trans_validate(tr);
562
563
564 if (valide) {
565 store_unlock();
566 if (sql_save_snapshots(tr) != SQL_OK) {
567 char *err = sql_message(SQLSTATE(40000) "%s transaction commit failed (perhaps your disk is full?) exiting (kernel error: %s)", operation, GDKerrbuf);
568 GDKfatal("%s", err);
569 _DELETE(err);
570 }
571 store_lock();
572 }
573 valide = sql_trans_validate(tr);
574 if (valide) {
575 if ((ok = sql_trans_commit(tr)) != SQL_OK) {
576 char *err = sql_message(SQLSTATE(40000) "%s transaction commit failed (perhaps your disk is full?) exiting (kernel error: %s)", operation, GDKerrbuf);
577 GDKfatal("%s", err);
578 _DELETE(err);
579 }
580 } else {
581 store_unlock();
582 msg = createException(SQL, "sql.commit", SQLSTATE(40000) "%s transaction is aborted because of concurrency conflicts, will ROLLBACK instead", operation);
583 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
584 freeException(other);
585 return msg;
586 }
587 msg = WLCcommit(m->clientid);
588 if(msg != MAL_SUCCEED) {
589 store_unlock();
590 if((other = mvc_rollback(m, chain, name, false)) != MAL_SUCCEED)
591 freeException(other);
592 return msg;
593 }
594 sql_trans_end(m->session);
595 if (chain)
596 sql_trans_begin(m->session);
597 store_unlock();
598 m->type = Q_TRANS;
599 if (mvc_debug)
600 fprintf(stderr, "#mvc_commit done\n");
601 if (GDKverbose >= 1)
602 fprintf(stderr, "#%s: commit done%s%.200s\n",
603 MT_thread_getname(),
604 GDKverbose >= 2 && m->query ? ", query: " : "",
605 GDKverbose >= 2 && m->query ? m->query : "");
606 return msg;
607}
608
609str
610mvc_rollback(mvc *m, int chain, const char *name, bool disabling_auto_commit)
611{
612 sql_trans *tr = m->session->tr;
613 str msg;
614
615 if (mvc_debug)
616 fprintf(stderr, "#mvc_rollback %s\n", (name) ? name : "");
617
618 assert(tr);
619 assert(m->session->tr->active); /* only abort an active transaction */
620 (void) disabling_auto_commit;
621
622 store_lock();
623 if (m->qc)
624 qc_clean(m->qc);
625 if (name && name[0] != '\0') {
626 while (tr && (!tr->name || strcmp(tr->name, name) != 0))
627 tr = tr->parent;
628 if (!tr) {
629 msg = createException(SQL, "sql.rollback", SQLSTATE(42000) "ROLLBACK TO SAVEPOINT: no such savepoint: '%s'", name);
630 m->session->status = -1;
631 store_unlock();
632 return msg;
633 }
634 tr = m->session->tr;
635 while (!tr->name || strcmp(tr->name, name) != 0) {
636 /* make sure we do not reuse changed data */
637 if (tr->wtime)
638 tr->status = 1;
639 tr = sql_trans_destroy(tr, true);
640 }
641 m->session->tr = tr; /* restart at savepoint */
642 m->session->status = tr->status;
643 if (tr->name)
644 tr->name = NULL;
645 m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name);
646 } else if (tr->parent) {
647 /* first release all intermediate savepoints */
648 while (tr->parent->parent != NULL) {
649 tr = sql_trans_destroy(tr, true);
650 }
651 m->session-> tr = tr;
652 /* make sure we do not reuse changed data */
653 if (tr->wtime)
654 tr->status = 1;
655 sql_trans_end(m->session);
656 if (chain)
657 sql_trans_begin(m->session);
658 }
659 msg = WLCrollback(m->clientid);
660 store_unlock();
661 if (msg != MAL_SUCCEED) {
662 m->session->status = -1;
663 return msg;
664 }
665 m->type = Q_TRANS;
666 if (mvc_debug)
667 fprintf(stderr, "#mvc_rollback %s done\n", (name) ? name : "");
668 if (GDKverbose >= 1)
669 fprintf(stderr, "#%s: commit%s%s rolled back%s%s%.200s\n",
670 MT_thread_getname(), name ? " " : "", name ? name : "",
671 tr->wtime == 0 ? " (no changes)" : "",
672 GDKverbose >= 2 && m->query ? ", query: " : "",
673 GDKverbose >= 2 && m->query ? m->query : "");
674 return msg;
675}
676
677/* release all savepoints up including the given named savepoint
678 * but keep the current changes.
679 * */
680str
681mvc_release(mvc *m, const char *name)
682{
683 int ok = SQL_OK;
684 sql_trans *tr = m->session->tr;
685 str msg = MAL_SUCCEED;
686
687 assert(tr);
688 assert(m->session->tr->active); /* only release active transactions */
689
690 if (mvc_debug)
691 fprintf(stderr, "#mvc_release %s\n", (name) ? name : "");
692
693 if (!name && (msg = mvc_rollback(m, 0, name, false)) != MAL_SUCCEED) {
694 m->session->status = -1;
695 return msg;
696 }
697
698 while (tr && (!tr->name || strcmp(tr->name, name) != 0))
699 tr = tr->parent;
700 if (!tr || !tr->name || strcmp(tr->name, name) != 0) {
701 msg = createException(SQL, "sql.release", SQLSTATE(42000) "Release savepoint %s doesn't exist", name);
702 m->session->status = -1;
703 return msg;
704 }
705 tr = m->session->tr;
706 store_lock();
707 while (ok == SQL_OK && (!tr->name || strcmp(tr->name, name) != 0)) {
708 /* commit all intermediate savepoints */
709 if (sql_trans_commit(tr) != SQL_OK)
710 GDKfatal("release savepoints should not fail");
711 tr = sql_trans_destroy(tr, true);
712 }
713 tr->name = NULL;
714 store_unlock();
715 m->session->tr = tr;
716 m->session->schema = find_sql_schema(m->session->tr, m->session->schema_name);
717
718 m->type = Q_TRANS;
719 return msg;
720}
721
722mvc *
723mvc_create(int clientid, backend_stack stk, int debug, bstream *rs, stream *ws)
724{
725 int i;
726 mvc *m;
727
728 m = ZNEW(mvc);
729 if(!m) {
730 return NULL;
731 }
732 if (mvc_debug)
733 fprintf(stderr, "#mvc_create\n");
734
735 m->errstr[0] = '\0';
736 /* if an error exceeds the buffer we don't want garbage at the end */
737 m->errstr[ERRSIZE-1] = '\0';
738
739 m->qc = qc_create(clientid, 0);
740 if(!m->qc) {
741 _DELETE(m);
742 return NULL;
743 }
744 m->sa = NULL;
745
746 m->params = NULL;
747 m->sizevars = MAXPARAMS;
748 m->vars = NEW_ARRAY(sql_var, m->sizevars);
749
750 m->topvars = 0;
751 m->frame = 1;
752 m->use_views = 0;
753 m->argmax = MAXPARAMS;
754 m->args = NEW_ARRAY(atom*,m->argmax);
755 if(!m->vars || !m->args) {
756 qc_destroy(m->qc);
757 _DELETE(m->vars);
758 _DELETE(m->args);
759 _DELETE(m);
760 return NULL;
761 }
762 m->argc = 0;
763 m->sym = NULL;
764
765 m->Topt = 0;
766 m->rowcnt = m->last_id = m->role_id = m->user_id = -1;
767 m->timezone = 0;
768 m->clientid = clientid;
769
770 m->emode = m_normal;
771 m->emod = mod_none;
772 m->reply_size = 100;
773 m->debug = debug;
774 m->cache = DEFAULT_CACHESIZE;
775 m->caching = m->cache;
776
777 m->label = 0;
778 m->remote = 0;
779 m->cascade_action = NULL;
780 for(i=0;i<MAXSTATS;i++)
781 m->opt_stats[i] = 0;
782
783 store_lock();
784 m->session = sql_session_create(stk, 1 /*autocommit on*/);
785 store_unlock();
786 if(!m->session) {
787 qc_destroy(m->qc);
788 _DELETE(m->vars);
789 _DELETE(m->args);
790 _DELETE(m);
791 return NULL;
792 }
793
794 m->type = Q_PARSE;
795 m->pushdown = 1;
796
797 m->result_id = 0;
798 m->results = NULL;
799
800 scanner_init(&m->scanner, rs, ws);
801 return m;
802}
803
804int
805mvc_reset(mvc *m, bstream *rs, stream *ws, int debug, int globalvars)
806{
807 int i, res = 1;
808 sql_trans *tr;
809
810 if (mvc_debug)
811 fprintf(stderr, "#mvc_reset\n");
812 tr = m->session->tr;
813 if (tr && tr->parent) {
814 assert(m->session->tr->active == 0);
815 store_lock();
816 while (tr->parent->parent != NULL)
817 tr = sql_trans_destroy(tr, true);
818 store_unlock();
819 }
820 if (tr && !sql_session_reset(m->session, 1 /*autocommit on*/))
821 res = 0;
822
823 if (m->sa)
824 m->sa = sa_reset(m->sa);
825 else
826 m->sa = sa_create();
827 if(!m->sa)
828 res = 0;
829
830 m->errstr[0] = '\0';
831
832 m->params = NULL;
833 /* reset topvars to the set of global variables */
834 stack_pop_until(m, globalvars);
835 m->frame = 1;
836 m->argc = 0;
837 m->sym = NULL;
838
839 m->Topt = 0;
840 m->rowcnt = m->last_id = m->role_id = m->user_id = -1;
841 m->emode = m_normal;
842 m->emod = mod_none;
843 if (m->reply_size != 100)
844 stack_set_number(m, "reply_size", 100);
845 m->reply_size = 100;
846 if (m->timezone != 0)
847 stack_set_number(m, "current_timezone", 0);
848 m->timezone = 0;
849 if (m->debug != debug)
850 stack_set_number(m, "debug", debug);
851 m->debug = debug;
852 if (m->cache != DEFAULT_CACHESIZE)
853 stack_set_number(m, "cache", DEFAULT_CACHESIZE);
854 m->cache = DEFAULT_CACHESIZE;
855 m->caching = m->cache;
856
857 m->label = 0;
858 m->remote = 0;
859 m->cascade_action = NULL;
860 m->type = Q_PARSE;
861 m->pushdown = 1;
862
863 for(i=0;i<MAXSTATS;i++)
864 m->opt_stats[i] = 0;
865
866 m->result_id = 0;
867 m->results = NULL;
868
869 scanner_init(&m->scanner, rs, ws);
870 return res;
871}
872
873void
874mvc_destroy(mvc *m)
875{
876 sql_trans *tr;
877
878 if (mvc_debug)
879 fprintf(stderr, "#mvc_destroy\n");
880 tr = m->session->tr;
881 if (tr) {
882 store_lock();
883 if (m->session->tr->active)
884 sql_trans_end(m->session);
885 while (tr->parent)
886 tr = sql_trans_destroy(tr, true);
887 m->session->tr = NULL;
888 store_unlock();
889 }
890 sql_session_destroy(m->session);
891
892 stack_pop_until(m, 0);
893 _DELETE(m->vars);
894
895 if (m->scanner.log) /* close and destroy stream */
896 close_stream(m->scanner.log);
897
898 if (m->sa)
899 sa_destroy(m->sa);
900 m->sa = NULL;
901 if (m->qc)
902 qc_destroy(m->qc);
903 m->qc = NULL;
904
905 _DELETE(m->args);
906 _DELETE(m->query);
907 m->args = NULL;
908 _DELETE(m);
909}
910
911sql_type *
912mvc_bind_type(mvc *sql, const char *name)
913{
914 sql_type *t = sql_trans_bind_type(sql->session->tr, NULL, name);
915
916 if (mvc_debug)
917 fprintf(stderr, "#mvc_bind_type %s\n", name);
918 return t;
919}
920
921sql_type *
922schema_bind_type(mvc *sql, sql_schema *s, const char *name)
923{
924 sql_type *t = find_sql_type(s, name);
925
926 (void) sql;
927 if (!t)
928 return NULL;
929 if (mvc_debug)
930 fprintf(stderr, "#schema_bind_type %s\n", name);
931 return t;
932}
933
934sql_func *
935mvc_bind_func(mvc *sql, const char *name)
936{
937 sql_func *t = sql_trans_bind_func(sql->session->tr, name);
938
939 if (mvc_debug)
940 fprintf(stderr, "#mvc_bind_func %s\n", name);
941 return t;
942}
943
944list *
945schema_bind_func(mvc *sql, sql_schema * s, const char *name, sql_ftype type)
946{
947 list *func_list = find_all_sql_func(s, name, type);
948
949 (void) sql;
950 if (!func_list)
951 return NULL;
952 if (mvc_debug)
953 fprintf(stderr, "#schema_bind_func %s\n", name);
954 return func_list;
955}
956
957sql_schema *
958mvc_bind_schema(mvc *m, const char *sname)
959{
960 sql_trans *tr = m->session->tr;
961 sql_schema *s;
962
963 if (!tr)
964 return NULL;
965
966 /* declared tables */
967 if (strcmp(sname, str_nil) == 0)
968 sname = dt_schema;
969 s = find_sql_schema(tr, sname);
970 if (!s)
971 return NULL;
972
973 if (mvc_debug)
974 fprintf(stderr, "#mvc_bind_schema %s\n", sname);
975 return s;
976}
977
978sql_table *
979mvc_bind_table(mvc *m, sql_schema *s, const char *tname)
980{
981 sql_table *t = NULL;
982
983 if (!s) { /* Declared tables during query compilation have no schema */
984 sql_table *tpe = stack_find_table(m, tname);
985 if (tpe) {
986 t = tpe;
987 } else { /* during exection they are in the declared table schema */
988 s = mvc_bind_schema(m, dt_schema);
989 return mvc_bind_table(m, s, tname);
990 }
991 } else {
992 t = find_sql_table(s, tname);
993 }
994 if (!t)
995 return NULL;
996 if (mvc_debug)
997 fprintf(stderr, "#mvc_bind_table %s.%s\n", s ? s->base.name : "<noschema>", tname);
998
999 return t;
1000}
1001
1002sql_column *
1003mvc_bind_column(mvc *m, sql_table *t, const char *cname)
1004{
1005 sql_column *c;
1006
1007 (void)m;
1008 c = find_sql_column(t, cname);
1009 if (!c)
1010 return NULL;
1011 if (mvc_debug)
1012 fprintf(stderr, "#mvc_bind_column %s.%s\n", t->base.name, cname);
1013 return c;
1014}
1015
1016static sql_column *
1017first_column(sql_table *t)
1018{
1019 node *n = cs_first_node(&t->columns);
1020
1021 if (n)
1022 return n->data;
1023 return NULL;
1024}
1025
1026
1027sql_column *
1028mvc_first_column(mvc *m, sql_table *t)
1029{
1030 sql_column *c = first_column(t);
1031
1032 (void) m;
1033 if (!c)
1034 return NULL;
1035 if (mvc_debug)
1036 fprintf(stderr, "#mvc_first_column %s.%s\n", t->base.name, c->base.name);
1037
1038 return c;
1039}
1040
1041sql_key *
1042mvc_bind_key(mvc *m, sql_schema *s, const char *kname)
1043{
1044 node *n = list_find_name(s->keys, kname);
1045 sql_key *k;
1046
1047 (void) m;
1048 if (!n)
1049 return NULL;
1050 k = n->data;
1051
1052 if (mvc_debug)
1053 fprintf(stderr, "#mvc_bind_key %s.%s\n", s->base.name, kname);
1054
1055 return k;
1056}
1057
1058sql_idx *
1059mvc_bind_idx(mvc *m, sql_schema *s, const char *iname)
1060{
1061 node *n = list_find_name(s->idxs, iname);
1062 sql_idx *i;
1063
1064 (void) m;
1065 if (!n)
1066 return NULL;
1067 i = n->data;
1068
1069 if (mvc_debug)
1070 fprintf(stderr, "#mvc_bind_idx %s.%s\n", s->base.name, iname);
1071
1072 return i;
1073}
1074
1075static int
1076uniqueKey(sql_key *k)
1077{
1078 return (k->type == pkey || k->type == ukey);
1079}
1080
1081sql_key *
1082mvc_bind_ukey(sql_table *t, list *colnames)
1083{
1084 node *cn;
1085 node *cur;
1086 sql_key *res = NULL;
1087 int len = list_length(colnames);
1088
1089 if (cs_size(&t->keys))
1090 for (cur = t->keys.set->h; cur; cur = cur->next) {
1091 node *cc;
1092 sql_key *k = cur->data;
1093
1094 if (uniqueKey(k) && list_length(k->columns) == len) {
1095 res = k;
1096 for (cc = k->columns->h, cn = colnames->h; cc && cn; cc = cc->next, cn = cn->next) {
1097 sql_kc *c = cc->data;
1098 char *n = cn->data;
1099
1100 if (strcmp(c->c->base.name, n) != 0) {
1101 res = NULL;
1102 break;
1103 }
1104 }
1105 if (res)
1106 break;
1107 }
1108 }
1109 return res;
1110}
1111
1112sql_trigger *
1113mvc_bind_trigger(mvc *m, sql_schema *s, const char *tname)
1114{
1115 node *n = list_find_name(s->triggers, tname);
1116 sql_trigger *trigger;
1117
1118 (void) m;
1119 if (!n)
1120 return NULL;
1121 trigger = n->data;
1122
1123 if (mvc_debug)
1124 fprintf(stderr, "#mvc_bind_trigger %s.%s\n", s->base.name, tname);
1125
1126 return trigger;
1127}
1128
1129sql_type *
1130mvc_create_type(mvc *sql, sql_schema * s, const char *name, int digits, int scale, int radix, const char *impl)
1131{
1132 sql_type *t = NULL;
1133
1134 if (mvc_debug)
1135 fprintf(stderr, "#mvc_create_type %s\n", name);
1136
1137 t = sql_trans_create_type(sql->session->tr, s, name, digits, scale, radix, impl);
1138 return t;
1139}
1140
1141int
1142mvc_drop_type(mvc *m, sql_schema *s, sql_type *t, int drop_action)
1143{
1144 if (mvc_debug)
1145 fprintf(stderr, "#mvc_drop_type %s %s\n", s->base.name, t->base.name);
1146
1147 if (t)
1148 return sql_trans_drop_type(m->session->tr, s, t->base.id, drop_action);
1149 return 0;
1150}
1151
1152sql_func *
1153mvc_create_func(mvc *sql, sql_allocator *sa, sql_schema *s, const char *name, list *args, list *res, sql_ftype type, sql_flang lang, const char *mod, const char *impl, const char *query, bit varres, bit vararg, bit system)
1154{
1155 sql_func *f = NULL;
1156
1157 if (mvc_debug)
1158 fprintf(stderr, "#mvc_create_func %s\n", name);
1159 if (sa) {
1160 f = create_sql_func(sa, name, args, res, type, lang, mod, impl, query, varres, vararg, system);
1161 f->s = s;
1162 } else
1163 f = sql_trans_create_func(sql->session->tr, s, name, args, res, type, lang, mod, impl, query, varres, vararg, system);
1164 return f;
1165}
1166
1167int
1168mvc_drop_func(mvc *m, sql_schema *s, sql_func *f, int drop_action)
1169{
1170 if (mvc_debug)
1171 fprintf(stderr, "#mvc_drop_func %s %s\n", s->base.name, f->base.name);
1172
1173 return sql_trans_drop_func(m->session->tr, s, f->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1174}
1175
1176int
1177mvc_drop_all_func(mvc *m, sql_schema *s, list *list_func, int drop_action)
1178{
1179 if (mvc_debug)
1180 fprintf(stderr, "#mvc_drop_all_func %s %s\n", s->base.name, ((sql_func *) list_func->h->data)->base.name);
1181
1182 return sql_trans_drop_all_func(m->session->tr, s, list_func, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1183}
1184
1185sql_schema *
1186mvc_create_schema(mvc *m, const char *name, sqlid auth_id, sqlid owner)
1187{
1188 sql_schema *s = NULL;
1189
1190 if (mvc_debug)
1191 fprintf(stderr, "#mvc_create_schema %s %d %d\n", name, auth_id, owner);
1192
1193 s = sql_trans_create_schema(m->session->tr, name, auth_id, owner);
1194 return s;
1195}
1196
1197int
1198mvc_drop_schema(mvc *m, sql_schema * s, int drop_action)
1199{
1200 if (mvc_debug)
1201 fprintf(stderr, "#mvc_drop_schema %s\n", s->base.name);
1202 return sql_trans_drop_schema(m->session->tr, s->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1203}
1204
1205sql_ukey *
1206mvc_create_ukey(mvc *m, sql_table *t, const char *name, key_type kt)
1207{
1208 if (mvc_debug)
1209 fprintf(stderr, "#mvc_create_ukey %s %u\n", t->base.name, kt);
1210 if (t->persistence == SQL_DECLARED_TABLE)
1211 return create_sql_ukey(m->sa, t, name, kt);
1212 else
1213 return (sql_ukey*)sql_trans_create_ukey(m->session->tr, t, name, kt);
1214}
1215
1216sql_key *
1217mvc_create_ukey_done(mvc *m, sql_key *k)
1218{
1219 if (k->t->persistence == SQL_DECLARED_TABLE)
1220 return key_create_done(m->sa, k);
1221 else
1222 return sql_trans_key_done(m->session->tr, k);
1223}
1224
1225sql_fkey *
1226mvc_create_fkey(mvc *m, sql_table *t, const char *name, key_type kt, sql_key *rkey, int on_delete, int on_update)
1227{
1228 if (mvc_debug)
1229 fprintf(stderr, "#mvc_create_fkey %s %u %p\n", t->base.name, kt, rkey);
1230 if (t->persistence == SQL_DECLARED_TABLE)
1231 return create_sql_fkey(m->sa, t, name, kt, rkey, on_delete, on_update);
1232 else
1233 return sql_trans_create_fkey(m->session->tr, t, name, kt, rkey, on_delete, on_update);
1234}
1235
1236sql_key *
1237mvc_create_kc(mvc *m, sql_key *k, sql_column *c)
1238{
1239 if (k->t->persistence == SQL_DECLARED_TABLE)
1240 return create_sql_kc(m->sa, k, c);
1241 else
1242 return sql_trans_create_kc(m->session->tr, k, c);
1243}
1244
1245sql_fkey *
1246mvc_create_fkc(mvc *m, sql_fkey *fk, sql_column *c)
1247{
1248 sql_key *k = (sql_key*)fk;
1249
1250 if (k->t->persistence == SQL_DECLARED_TABLE)
1251 return (sql_fkey*)create_sql_kc(m->sa, k, c);
1252 else
1253 return sql_trans_create_fkc(m->session->tr, fk, c);
1254}
1255
1256int
1257mvc_drop_key(mvc *m, sql_schema *s, sql_key *k, int drop_action)
1258{
1259 if (mvc_debug)
1260 fprintf(stderr, "#mvc_drop_key %s %s\n", s->base.name, k->base.name);
1261 if (k->t->persistence == SQL_DECLARED_TABLE) {
1262 drop_sql_key(k->t, k->base.id, drop_action);
1263 return 0;
1264 } else
1265 return sql_trans_drop_key(m->session->tr, s, k->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1266}
1267
1268sql_idx *
1269mvc_create_idx(mvc *m, sql_table *t, const char *name, idx_type it)
1270{
1271 sql_idx *i;
1272
1273 if (mvc_debug)
1274 fprintf(stderr, "#mvc_create_idx %s %u\n", t->base.name, it);
1275
1276 if (t->persistence == SQL_DECLARED_TABLE)
1277 /* declared tables should not end up in the catalog */
1278 return create_sql_idx(m->sa, t, name, it);
1279 else
1280 i = sql_trans_create_idx(m->session->tr, t, name, it);
1281 return i;
1282}
1283
1284sql_idx *
1285mvc_create_ic(mvc *m, sql_idx * i, sql_column *c)
1286{
1287 if (i->t->persistence == SQL_DECLARED_TABLE)
1288 /* declared tables should not end up in the catalog */
1289 return create_sql_ic(m->sa, i, c);
1290 else
1291 return sql_trans_create_ic(m->session->tr, i, c);
1292}
1293
1294int
1295mvc_drop_idx(mvc *m, sql_schema *s, sql_idx *i)
1296{
1297 if (mvc_debug)
1298 fprintf(stderr, "#mvc_drop_idx %s %s\n", s->base.name, i->base.name);
1299
1300 if (i->t->persistence == SQL_DECLARED_TABLE) {
1301 /* declared tables should not end up in the catalog */
1302 drop_sql_idx(i->t, i->base.id);
1303 return 0;
1304 } else
1305 return sql_trans_drop_idx(m->session->tr, s, i->base.id, DROP_RESTRICT);
1306}
1307
1308sql_trigger *
1309mvc_create_trigger(mvc *m, sql_table *t, const char *name, sht time, sht orientation, sht event, const char *old_name, const char *new_name, const char *condition, const char *statement )
1310{
1311 sql_trigger *i;
1312
1313 if (mvc_debug)
1314 fprintf(stderr, "#mvc_create_trigger %s %d %d %d\n", t->base.name, time, orientation, event);
1315
1316 i = sql_trans_create_trigger(m->session->tr, t, name, time, orientation,
1317 event, old_name, new_name, condition, statement);
1318 return i;
1319}
1320
1321sql_trigger *
1322mvc_create_tc(mvc *m, sql_trigger * i, sql_column *c /*, extra options such as trunc */ )
1323{
1324 sql_trans_create_tc(m->session->tr, i, c);
1325 return i;
1326}
1327
1328int
1329mvc_drop_trigger(mvc *m, sql_schema *s, sql_trigger *tri)
1330{
1331 if (mvc_debug)
1332 fprintf(stderr, "#mvc_drop_trigger %s %s\n", s->base.name, tri->base.name);
1333
1334 return sql_trans_drop_trigger(m->session->tr, s, tri->base.id, DROP_RESTRICT);
1335}
1336
1337
1338sql_table *
1339mvc_create_table(mvc *m, sql_schema *s, const char *name, int tt, bit system, int persistence, int commit_action, int sz, bit properties)
1340{
1341 sql_table *t = NULL;
1342 char *err = NULL;
1343 int check = 0;
1344
1345 if (mvc_debug)
1346 fprintf(stderr, "#mvc_create_table %s %s %d %d %d %d %d\n", s->base.name, name, tt, system, persistence, commit_action, (int)properties);
1347
1348 if (persistence == SQL_DECLARED_TABLE && (!s || strcmp(s->base.name, dt_schema))) {
1349 t = create_sql_table(m->sa, name, tt, system, persistence, commit_action, properties);
1350 t->s = s;
1351 } else {
1352 t = sql_trans_create_table(m->session->tr, s, name, NULL, tt, system, persistence, commit_action, sz, properties);
1353 if(t && isPartitionedByExpressionTable(t) && (err = bootstrap_partition_expression(m, m->session->tr->sa, t, 1))) {
1354 (void) sql_error(m, 02, "%s", err);
1355 return NULL;
1356 }
1357 check = sql_trans_set_partition_table(m->session->tr, t);
1358 if(check == -1) {
1359 (void) sql_error(m, 02, SQLSTATE(42000) "CREATE TABLE: %s_%s: the partition's expression is too long", s->base.name, t->base.name);
1360 return NULL;
1361 } else if (check) {
1362 (void) sql_error(m, 02, SQLSTATE(42000) "CREATE TABLE: %s_%s: an internal error occurred", s->base.name, t->base.name);
1363 return NULL;
1364 }
1365 }
1366 return t;
1367}
1368
1369sql_table *
1370mvc_create_view(mvc *m, sql_schema *s, const char *name, int persistence, const char *sql, bit system)
1371{
1372 sql_table *t = NULL;
1373
1374 if (mvc_debug)
1375 fprintf(stderr, "#mvc_create_view %s %s %s\n", s->base.name, name, sql);
1376
1377 if (persistence == SQL_DECLARED_TABLE) {
1378 t = create_sql_table(m->sa, name, tt_view, system, persistence, 0, 0);
1379 t->s = s;
1380 t->query = sa_strdup(m->sa, sql);
1381 } else {
1382 t = sql_trans_create_table(m->session->tr, s, name, sql, tt_view, system, SQL_PERSIST, 0, 0, 0);
1383 }
1384 return t;
1385}
1386
1387sql_table *
1388mvc_create_remote(mvc *m, sql_schema *s, const char *name, int persistence, const char *loc)
1389{
1390 sql_table *t = NULL;
1391
1392 if (mvc_debug)
1393 fprintf(stderr, "#mvc_create_remote %s %s %s\n", s->base.name, name, loc);
1394
1395 if (persistence == SQL_DECLARED_TABLE) {
1396 t = create_sql_table(m->sa, name, tt_remote, 0, persistence, 0, 0);
1397 t->s = s;
1398 t->query = sa_strdup(m->sa, loc);
1399 } else {
1400 t = sql_trans_create_table(m->session->tr, s, name, loc, tt_remote, 0, SQL_REMOTE, 0, 0, 0);
1401 }
1402 return t;
1403}
1404
1405str
1406mvc_drop_table(mvc *m, sql_schema *s, sql_table *t, int drop_action)
1407{
1408 if (mvc_debug)
1409 fprintf(stderr, "#mvc_drop_table %s %s\n", s->base.name, t->base.name);
1410
1411 if (isRemote(t)) {
1412 str AUTHres;
1413 sql_allocator *sa = m->sa;
1414
1415 m->sa = sa_create();
1416 if (!m->sa)
1417 throw(SQL, "sql.mvc_drop_table", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1418 char *qualified_name = sa_strconcat(m->sa, sa_strconcat(m->sa, t->s->base.name, "."), t->base.name);
1419 if (!qualified_name) {
1420 sa_destroy(m->sa);
1421 m->sa = sa;
1422 throw(SQL, "sql.mvc_drop_table", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1423 }
1424
1425 AUTHres = AUTHdeleteRemoteTableCredentials(qualified_name);
1426 sa_destroy(m->sa);
1427 m->sa = sa;
1428
1429 if(AUTHres != MAL_SUCCEED)
1430 return AUTHres;
1431 }
1432
1433 if(sql_trans_drop_table(m->session->tr, s, t->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT))
1434 throw(SQL, "sql.mvc_drop_table", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1435 return MAL_SUCCEED;
1436}
1437
1438BUN
1439mvc_clear_table(mvc *m, sql_table *t)
1440{
1441 return sql_trans_clear_table(m->session->tr, t);
1442}
1443
1444sql_column *
1445mvc_create_column_(mvc *m, sql_table *t, const char *name, const char *type, int digits)
1446{
1447 sql_subtype tpe;
1448
1449 if (!sql_find_subtype(&tpe, type, digits, 0))
1450 return NULL;
1451
1452 return sql_trans_create_column(m->session->tr, t, name, &tpe);
1453}
1454
1455sql_column *
1456mvc_create_column(mvc *m, sql_table *t, const char *name, sql_subtype *tpe)
1457{
1458 if (mvc_debug)
1459 fprintf(stderr, "#mvc_create_column %s %s %s\n", t->base.name, name, tpe->type->sqlname);
1460 if (t->persistence == SQL_DECLARED_TABLE && (!t->s || strcmp(t->s->base.name, dt_schema)))
1461 /* declared tables should not end up in the catalog */
1462 return create_sql_column(m->sa, t, name, tpe);
1463 else
1464 return sql_trans_create_column(m->session->tr, t, name, tpe);
1465}
1466
1467int
1468mvc_drop_column(mvc *m, sql_table *t, sql_column *col, int drop_action)
1469{
1470 if (mvc_debug)
1471 fprintf(stderr, "#mvc_drop_column %s %s\n", t->base.name, col->base.name);
1472 if (col->t->persistence == SQL_DECLARED_TABLE) {
1473 drop_sql_column(t, col->base.id, drop_action);
1474 return 0;
1475 } else
1476 return sql_trans_drop_column(m->session->tr, t, col->base.id, drop_action ? DROP_CASCADE_START : DROP_RESTRICT);
1477}
1478
1479void
1480mvc_create_dependency(mvc *m, sqlid id, sqlid depend_id, sql_dependency depend_type)
1481{
1482 if (mvc_debug)
1483 fprintf(stderr, "#mvc_create_dependency %d %d %d\n", id, depend_id, (int) depend_type);
1484 if ( (id != depend_id) || (depend_type == BEDROPPED_DEPENDENCY) )
1485 sql_trans_create_dependency(m->session->tr, id, depend_id, depend_type);
1486}
1487
1488void
1489mvc_create_dependencies(mvc *m, list *id_l, sqlid depend_id, sql_dependency dep_type)
1490{
1491 node *n = id_l->h;
1492 int i;
1493
1494 if (mvc_debug)
1495 fprintf(stderr, "#mvc_create_dependencies on %d of type %d\n", depend_id, (int) dep_type);
1496
1497 for (i = 0; i < list_length(id_l); i++)
1498 {
1499 mvc_create_dependency(m, *(sqlid *) n->data, depend_id, dep_type);
1500 n = n->next;
1501 }
1502}
1503
1504int
1505mvc_check_dependency(mvc * m, sqlid id, sql_dependency type, list *ignore_ids)
1506{
1507 list *dep_list = NULL;
1508
1509 if (mvc_debug)
1510 fprintf(stderr, "#mvc_check_dependency on %d\n", id);
1511
1512 switch (type) {
1513 case OWNER_DEPENDENCY:
1514 dep_list = sql_trans_owner_schema_dependencies(m->session->tr, id);
1515 break;
1516 case SCHEMA_DEPENDENCY:
1517 dep_list = sql_trans_schema_user_dependencies(m->session->tr, id);
1518 break;
1519 case TABLE_DEPENDENCY:
1520 dep_list = sql_trans_get_dependencies(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1521 break;
1522 case VIEW_DEPENDENCY:
1523 dep_list = sql_trans_get_dependencies(m->session->tr, id, TABLE_DEPENDENCY, NULL);
1524 break;
1525 case FUNC_DEPENDENCY:
1526 case PROC_DEPENDENCY:
1527 dep_list = sql_trans_get_dependencies(m->session->tr, id, FUNC_DEPENDENCY, ignore_ids);
1528 break;
1529 default:
1530 dep_list = sql_trans_get_dependencies(m->session->tr, id, COLUMN_DEPENDENCY, NULL);
1531 }
1532
1533 if (!dep_list)
1534 return DEPENDENCY_CHECK_ERROR;
1535
1536 if (list_length(dep_list) >= 2) {
1537 list_destroy(dep_list);
1538 return HAS_DEPENDENCY;
1539 }
1540
1541 list_destroy(dep_list);
1542 return NO_DEPENDENCY;
1543}
1544
1545sql_column *
1546mvc_null(mvc *m, sql_column *col, int isnull)
1547{
1548 if (mvc_debug)
1549 fprintf(stderr, "#mvc_null %s %d\n", col->base.name, isnull);
1550
1551 if (col->t->persistence == SQL_DECLARED_TABLE) {
1552 col->null = isnull;
1553 return col;
1554 }
1555 return sql_trans_alter_null(m->session->tr, col, isnull);
1556}
1557
1558sql_column *
1559mvc_default(mvc *m, sql_column *col, char *val)
1560{
1561 if (mvc_debug)
1562 fprintf(stderr, "#mvc_default %s %s\n", col->base.name, val);
1563
1564 if (col->t->persistence == SQL_DECLARED_TABLE) {
1565 col->def = val?sa_strdup(m->sa, val):NULL;
1566 return col;
1567 } else {
1568 return sql_trans_alter_default(m->session->tr, col, val);
1569 }
1570}
1571
1572sql_column *
1573mvc_drop_default(mvc *m, sql_column *col)
1574{
1575 if (mvc_debug)
1576 fprintf(stderr, "#mvc_drop_default %s\n", col->base.name);
1577
1578 if (col->t->persistence == SQL_DECLARED_TABLE) {
1579 col->def = NULL;
1580 return col;
1581 } else {
1582 return sql_trans_alter_default(m->session->tr, col, NULL);
1583 }
1584}
1585
1586sql_column *
1587mvc_storage(mvc *m, sql_column *col, char *storage)
1588{
1589 if (mvc_debug)
1590 fprintf(stderr, "#mvc_storage %s %s\n", col->base.name, storage);
1591
1592 if (col->t->persistence == SQL_DECLARED_TABLE) {
1593 col->storage_type = storage?sa_strdup(m->sa, storage):NULL;
1594 return col;
1595 } else {
1596 return sql_trans_alter_storage(m->session->tr, col, storage);
1597 }
1598}
1599
1600sql_table *
1601mvc_access(mvc *m, sql_table *t, sht access)
1602{
1603 if (mvc_debug)
1604 fprintf(stderr, "#mvc_access %s %d\n", t->base.name, access);
1605
1606 if (t->persistence == SQL_DECLARED_TABLE) {
1607 t->access = access;
1608 return t;
1609 }
1610 return sql_trans_alter_access(m->session->tr, t, access);
1611}
1612
1613int
1614mvc_is_sorted(mvc *m, sql_column *col)
1615{
1616 if (mvc_debug)
1617 fprintf(stderr, "#mvc_is_sorted %s\n", col->base.name);
1618
1619 return sql_trans_is_sorted(m->session->tr, col);
1620}
1621
1622/* variable management */
1623static sql_var*
1624stack_set(mvc *sql, int var, const char *name, sql_subtype *type, sql_rel *rel, sql_table *t, dlist *wdef, sql_groupby_expression *exp, int view, int frame)
1625{
1626 sql_var *v, *nvars;
1627 int nextsize = sql->sizevars;
1628 if (var == nextsize) {
1629 nextsize <<= 1;
1630 nvars = RENEW_ARRAY(sql_var,sql->vars,nextsize);
1631 if(!nvars) {
1632 return NULL;
1633 } else {
1634 sql->vars = nvars;
1635 sql->sizevars = nextsize;
1636 }
1637 }
1638 v = sql->vars+var;
1639
1640 v->name = NULL;
1641 atom_init( &v->a );
1642 v->rel = rel;
1643 v->t = t;
1644 v->view = view;
1645 v->frame = frame;
1646 v->visited = 0;
1647 v->wdef = wdef;
1648 v->exp = exp;
1649 if (type) {
1650 int tpe = type->type->localtype;
1651 VALset(&sql->vars[var].a.data, tpe, (ptr) ATOMnilptr(tpe));
1652 v->a.tpe = *type;
1653 }
1654 if (name) {
1655 v->name = _STRDUP(name);
1656 if(!v->name)
1657 return NULL;
1658 }
1659 return v;
1660}
1661
1662sql_var*
1663stack_push_var(mvc *sql, const char *name, sql_subtype *type)
1664{
1665 sql_var* res = stack_set(sql, sql->topvars, name, type, NULL, NULL, NULL, NULL, 0, 0);
1666 if(res)
1667 sql->topvars++;
1668 return res;
1669}
1670
1671sql_var*
1672stack_push_rel_var(mvc *sql, const char *name, sql_rel *var, sql_subtype *type)
1673{
1674 sql_var* res = stack_set(sql, sql->topvars, name, type, var, NULL, NULL, NULL, 0, 0);
1675 if(res)
1676 sql->topvars++;
1677 return res;
1678}
1679
1680sql_var*
1681stack_push_table(mvc *sql, const char *name, sql_rel *var, sql_table *t)
1682{
1683 sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, t, NULL, NULL, 0, 0);
1684 if(res)
1685 sql->topvars++;
1686 return res;
1687}
1688
1689sql_var*
1690stack_push_rel_view(mvc *sql, const char *name, sql_rel *var)
1691{
1692 sql_var* res = stack_set(sql, sql->topvars, name, NULL, var, NULL, NULL, NULL, 1, 0);
1693 if(res)
1694 sql->topvars++;
1695 return res;
1696}
1697
1698sql_var*
1699stack_push_window_def(mvc *sql, const char *name, dlist *wdef)
1700{
1701 sql_var* res = stack_set(sql, sql->topvars, name, NULL, NULL, NULL, wdef, NULL, 0, 0);
1702 if(res)
1703 sql->topvars++;
1704 return res;
1705}
1706
1707dlist *
1708stack_get_window_def(mvc *sql, const char *name, int *pos)
1709{
1710 for (int i = sql->topvars-1; i >= 0; i--) {
1711 if (!sql->vars[i].frame && sql->vars[i].wdef && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0) {
1712 if(pos)
1713 *pos = i;
1714 return sql->vars[i].wdef;
1715 }
1716 }
1717 return NULL;
1718}
1719
1720sql_var*
1721stack_push_groupby_expression(mvc *sql, symbol *def, sql_exp *exp)
1722{
1723 sql_var* res = NULL;
1724 sql_groupby_expression *sge = MNEW(sql_groupby_expression);
1725
1726 if(sge) {
1727 sge->sdef = def;
1728 sge->token = def->token;
1729 sge->exp = exp;
1730
1731 res = stack_set(sql, sql->topvars, NULL, NULL, NULL, NULL, NULL, sge, 0, 0);
1732 if(res)
1733 sql->topvars++;
1734 }
1735 return res;
1736}
1737
1738sql_exp*
1739stack_get_groupby_expression(mvc *sql, symbol *def)
1740{
1741 for (int i = sql->topvars-1; i >= 0; i--)
1742 if (!sql->vars[i].frame && sql->vars[i].exp && sql->vars[i].exp->token == def->token && symbol_cmp(sql, sql->vars[i].exp->sdef, def)==0)
1743 return sql->vars[i].exp->exp;
1744 return NULL;
1745}
1746
1747/* There could a possibility that this is vulnerable to a time-of-check, time-of-use race condition.
1748 * However this should never happen in the SQL compiler */
1749char
1750stack_check_var_visited(mvc *sql, int i)
1751{
1752 if(i < 0 || i >= sql->topvars)
1753 return 0;
1754 return sql->vars[i].visited;
1755}
1756
1757void
1758stack_set_var_visited(mvc *sql, int i)
1759{
1760 if(i < 0 || i >= sql->topvars)
1761 return;
1762 sql->vars[i].visited = 1;
1763}
1764
1765void
1766stack_clear_frame_visited_flag(mvc *sql)
1767{
1768 for (int i = sql->topvars-1; i >= 0 && !sql->vars[i].frame; i--)
1769 sql->vars[i].visited = 0;
1770}
1771
1772atom *
1773stack_set_var(mvc *sql, const char *name, ValRecord *v)
1774{
1775 int i;
1776 atom *res = NULL;
1777
1778 for (i = sql->topvars-1; i >= 0; i--) {
1779 if (!sql->vars[i].frame && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0) {
1780 VALclear(&sql->vars[i].a.data);
1781 if(VALcopy(&sql->vars[i].a.data, v) == NULL)
1782 return NULL;
1783 sql->vars[i].a.isnull = VALisnil(v);
1784 if (v->vtype == TYPE_flt)
1785 sql->vars[i].a.d = v->val.fval;
1786 else if (v->vtype == TYPE_dbl)
1787 sql->vars[i].a.d = v->val.dval;
1788 res = &sql->vars[i].a;
1789 }
1790 }
1791 return res;
1792}
1793
1794atom *
1795stack_get_var(mvc *sql, const char *name)
1796{
1797 int i;
1798
1799 for (i = sql->topvars-1; i >= 0; i--) {
1800 if (!sql->vars[i].frame && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0) {
1801 return &sql->vars[i].a;
1802 }
1803 }
1804 return NULL;
1805}
1806
1807sql_var*
1808stack_push_frame(mvc *sql, const char *name)
1809{
1810 sql_var* res = stack_set(sql, sql->topvars, name, NULL, NULL, NULL, NULL, NULL, 0, 1);
1811 if (res) {
1812 sql->topvars++;
1813 sql->frame++;
1814 }
1815 return res;
1816}
1817
1818void
1819stack_pop_until(mvc *sql, int top)
1820{
1821 while (sql->topvars > top) {
1822 sql_var *v = &sql->vars[--sql->topvars];
1823
1824 c_delete(v->name);
1825 VALclear(&v->a.data);
1826 v->a.data.vtype = 0;
1827 if (v->exp)
1828 _DELETE(v->exp);
1829 v->wdef = NULL;
1830 }
1831}
1832
1833void
1834stack_pop_frame(mvc *sql)
1835{
1836 while (!sql->vars[--sql->topvars].frame) {
1837 sql_var *v = &sql->vars[sql->topvars];
1838
1839 c_delete(v->name);
1840 VALclear(&v->a.data);
1841 v->a.data.vtype = 0;
1842 if (v->t && v->view)
1843 table_destroy(v->t);
1844 else if (v->rel)
1845 rel_destroy(v->rel);
1846 else if(v->exp)
1847 _DELETE(v->exp);
1848 v->wdef = NULL;
1849 }
1850 if (sql->vars[sql->topvars].name)
1851 c_delete(sql->vars[sql->topvars].name);
1852 sql->frame--;
1853}
1854
1855sql_subtype *
1856stack_find_type(mvc *sql, const char *name)
1857{
1858 int i;
1859
1860 for (i = sql->topvars-1; i >= 0; i--) {
1861 if (!sql->vars[i].frame && !sql->vars[i].view && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1862 return &sql->vars[i].a.tpe;
1863 }
1864 return NULL;
1865}
1866
1867sql_table *
1868stack_find_table(mvc *sql, const char *name)
1869{
1870 int i;
1871
1872 for (i = sql->topvars-1; i >= 0; i--) {
1873 if (!sql->vars[i].frame && !sql->vars[i].view && sql->vars[i].t
1874 && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1875 return sql->vars[i].t;
1876 }
1877 return NULL;
1878}
1879
1880sql_rel *
1881stack_find_rel_view(mvc *sql, const char *name)
1882{
1883 int i;
1884
1885 for (i = sql->topvars-1; i >= 0; i--) {
1886 if (!sql->vars[i].frame && sql->vars[i].view &&
1887 sql->vars[i].rel && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1888 return rel_dup(sql->vars[i].rel);
1889 }
1890 return NULL;
1891}
1892
1893void
1894stack_update_rel_view(mvc *sql, const char *name, sql_rel *view)
1895{
1896 int i;
1897
1898 for (i = sql->topvars-1; i >= 0; i--) {
1899 if (!sql->vars[i].frame && sql->vars[i].view &&
1900 sql->vars[i].rel && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0) {
1901 rel_destroy(sql->vars[i].rel);
1902 sql->vars[i].rel = view;
1903 }
1904 }
1905}
1906
1907int
1908stack_find_var(mvc *sql, const char *name)
1909{
1910 int i;
1911
1912 for (i = sql->topvars-1; i >= 0; i--) {
1913 if (!sql->vars[i].frame && !sql->vars[i].view && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1914 return 1;
1915 }
1916 return 0;
1917}
1918
1919sql_rel *
1920stack_find_rel_var(mvc *sql, const char *name)
1921{
1922 int i;
1923
1924 for (i = sql->topvars-1; i >= 0; i--) {
1925 if (!sql->vars[i].frame && !sql->vars[i].view &&
1926 sql->vars[i].rel && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1927 return rel_dup(sql->vars[i].rel);
1928 }
1929 return NULL;
1930}
1931
1932int
1933frame_find_var(mvc *sql, const char *name)
1934{
1935 int i;
1936
1937 for (i = sql->topvars-1; i >= 0 && !sql->vars[i].frame; i--) {
1938 if (sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1939 return 1;
1940 }
1941 return 0;
1942}
1943
1944int
1945stack_find_frame(mvc *sql, const char *name)
1946{
1947 int i, frame = sql->frame;
1948
1949 for (i = sql->topvars-1; i >= 0; i--) {
1950 if (sql->vars[i].frame)
1951 frame--;
1952 else if (sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1953 return frame;
1954 }
1955 return 0;
1956}
1957
1958int
1959stack_has_frame(mvc *sql, const char *name)
1960{
1961 int i;
1962
1963 for (i = sql->topvars-1; i >= 0; i--) {
1964 if (sql->vars[i].frame && sql->vars[i].name && strcmp(sql->vars[i].name, name)==0)
1965 return 1;
1966 }
1967 return 0;
1968}
1969
1970int
1971stack_nr_of_declared_tables(mvc *sql)
1972{
1973 int i, dt = 0;
1974
1975 for (i = sql->topvars-1; i >= 0; i--) {
1976 if (sql->vars[i].rel && !sql->vars[i].view) {
1977 sql_var *v = &sql->vars[i];
1978 if (v->t)
1979 dt++;
1980 }
1981 }
1982 return dt;
1983}
1984
1985str
1986stack_set_string(mvc *sql, const char *name, const char *val)
1987{
1988 atom *a = stack_get_var(sql, name);
1989 str new_val = _STRDUP(val);
1990
1991 if (a != NULL && new_val != NULL) {
1992 ValRecord *v = &a->data;
1993
1994 if (v->val.sval)
1995 _DELETE(v->val.sval);
1996 v->val.sval = new_val;
1997 return new_val;
1998 } else if(new_val) {
1999 _DELETE(new_val);
2000 }
2001 return NULL;
2002}
2003
2004str
2005stack_get_string(mvc *sql, const char *name)
2006{
2007 atom *a = stack_get_var(sql, name);
2008
2009 if (!a || a->data.vtype != TYPE_str)
2010 return NULL;
2011 return a->data.val.sval;
2012}
2013
2014void
2015#ifdef HAVE_HGE
2016stack_set_number(mvc *sql, const char *name, hge val)
2017#else
2018stack_set_number(mvc *sql, const char *name, lng val)
2019#endif
2020{
2021 atom *a = stack_get_var(sql, name);
2022
2023 if (a != NULL) {
2024 ValRecord *v = &a->data;
2025#ifdef HAVE_HGE
2026 if (v->vtype == TYPE_hge)
2027 v->val.hval = val;
2028#endif
2029 if (v->vtype == TYPE_lng)
2030 v->val.lval = val;
2031 if (v->vtype == TYPE_int)
2032 v->val.lval = (int) val;
2033 if (v->vtype == TYPE_sht)
2034 v->val.lval = (sht) val;
2035 if (v->vtype == TYPE_bte)
2036 v->val.lval = (bte) val;
2037 if (v->vtype == TYPE_bit) {
2038 if (val)
2039 v->val.btval = 1;
2040 else
2041 v->val.btval = 0;
2042 }
2043 }
2044}
2045
2046#ifdef HAVE_HGE
2047hge
2048#else
2049lng
2050#endif
2051val_get_number(ValRecord *v)
2052{
2053 if (v != NULL) {
2054#ifdef HAVE_HGE
2055 if (v->vtype == TYPE_hge)
2056 return v->val.hval;
2057#endif
2058 if (v->vtype == TYPE_lng)
2059 return v->val.lval;
2060 if (v->vtype == TYPE_int)
2061 return v->val.ival;
2062 if (v->vtype == TYPE_sht)
2063 return v->val.shval;
2064 if (v->vtype == TYPE_bte)
2065 return v->val.btval;
2066 if (v->vtype == TYPE_bit)
2067 if (v->val.btval)
2068 return 1;
2069 return 0;
2070 }
2071 return 0;
2072}
2073
2074#ifdef HAVE_HGE
2075hge
2076#else
2077lng
2078#endif
2079stack_get_number(mvc *sql, const char *name)
2080{
2081 atom *a = stack_get_var(sql, name);
2082 return val_get_number(a?&a->data:NULL);
2083}
2084
2085sql_column *
2086mvc_copy_column( mvc *m, sql_table *t, sql_column *c)
2087{
2088 return sql_trans_copy_column(m->session->tr, t, c);
2089}
2090
2091sql_key *
2092mvc_copy_key(mvc *m, sql_table *t, sql_key *k)
2093{
2094 return sql_trans_copy_key(m->session->tr, t, k);
2095}
2096
2097sql_idx *
2098mvc_copy_idx(mvc *m, sql_table *t, sql_idx *i)
2099{
2100 return sql_trans_copy_idx(m->session->tr, t, i);
2101}
2102
2103sql_trigger *
2104mvc_copy_trigger(mvc *m, sql_table *t, sql_trigger *tr)
2105{
2106 return sql_trans_copy_trigger(m->session->tr, t, tr);
2107}
2108
2109sql_part *
2110mvc_copy_part(mvc *m, sql_table *t, sql_part *pt)
2111{
2112 return sql_trans_copy_part(m->session->tr, t, pt);
2113}
2114
2115static inline int dlist_cmp(mvc *sql, dlist *l1, dlist *l2);
2116
2117static inline int
2118dnode_cmp(mvc *sql, dnode *d1, dnode *d2)
2119{
2120 if (d1 == d2)
2121 return 0;
2122
2123 if (!d1 || !d2)
2124 return -1;
2125
2126 if (d1->type == d2->type) {
2127 switch (d1->type) {
2128 case type_int:
2129 return (d1->data.i_val - d2->data.i_val);
2130 case type_lng: {
2131 lng c = d1->data.l_val - d2->data.l_val;
2132 assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
2133 return (int) c;
2134 }
2135 case type_string:
2136 if (d1->data.sval == d2->data.sval)
2137 return 0;
2138 if (!d1->data.sval || !d2->data.sval)
2139 return -1;
2140 return strcmp(d1->data.sval, d2->data.sval);
2141 case type_list:
2142 return dlist_cmp(sql, d1->data.lval, d2->data.lval);
2143 case type_symbol:
2144 return symbol_cmp(sql, d1->data.sym, d2->data.sym);
2145 case type_type:
2146 return subtype_cmp(&d1->data.typeval, &d2->data.typeval);
2147 default:
2148 assert(0);
2149 }
2150 }
2151 return -1;
2152}
2153
2154static inline int
2155dlist_cmp(mvc *sql, dlist *l1, dlist *l2)
2156{
2157 int res = 0;
2158 dnode *d1, *d2;
2159
2160 if (l1 == l2)
2161 return 0;
2162
2163 if (!l1 || !l2 || dlist_length(l1) != dlist_length(l2))
2164 return -1;
2165
2166 for (d1 = l1->h, d2 = l2->h; !res && d1; d1 = d1->next, d2 = d2->next) {
2167 res = dnode_cmp(sql, d1, d2);
2168 }
2169 return res;
2170}
2171
2172static inline int
2173AtomNodeCmp(AtomNode *a1, AtomNode *a2)
2174{
2175 if (a1 == a2)
2176 return 0;
2177 if (!a1 || !a2)
2178 return -1;
2179 if (a1->a && a2->a)
2180 return atom_cmp(a1->a, a2->a);
2181 return -1;
2182}
2183
2184static inline int
2185SelectNodeCmp(mvc *sql, SelectNode *s1, SelectNode *s2)
2186{
2187 if (s1 == s2)
2188 return 0;
2189 if (!s1 || !s2)
2190 return -1;
2191
2192 if (symbol_cmp(sql, s1->limit, s2->limit) == 0 &&
2193 symbol_cmp(sql, s1->offset, s2->offset) == 0 &&
2194 symbol_cmp(sql, s1->sample, s2->sample) == 0 &&
2195 s1->distinct == s2->distinct &&
2196 s1->lateral == s2->lateral &&
2197 symbol_cmp(sql, s1->name, s2->name) == 0 &&
2198 symbol_cmp(sql, s1->orderby, s2->orderby) == 0 &&
2199 symbol_cmp(sql, s1->having, s2->having) == 0 &&
2200 symbol_cmp(sql, s1->groupby, s2->groupby) == 0 &&
2201 symbol_cmp(sql, s1->where, s2->where) == 0 &&
2202 symbol_cmp(sql, s1->from, s2->from) == 0 &&
2203 symbol_cmp(sql, s1->window, s2->window) == 0 &&
2204 dlist_cmp(sql, s1->selection, s2->selection) == 0)
2205 return 0;
2206 return -1;
2207}
2208
2209static inline int
2210_symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
2211{
2212 if (s1 == s2)
2213 return 0;
2214 if (!s1 || !s2)
2215 return -1;
2216 if (s1->token != s2->token || s1->type != s2->type)
2217 return -1;
2218 switch (s1->type) {
2219 case type_int:
2220 return (s1->data.i_val - s2->data.i_val);
2221 case type_lng: {
2222 lng c = s1->data.l_val - s2->data.l_val;
2223 assert((lng) GDK_int_min <= c && c <= (lng) GDK_int_max);
2224 return (int) c;
2225 }
2226 case type_string:
2227 if (s1->data.sval == s2->data.sval)
2228 return 0;
2229 if (!s1->data.sval || !s2->data.sval)
2230 return -1;
2231 return strcmp(s1->data.sval, s2->data.sval);
2232 case type_list: {
2233 if (s1->token == SQL_IDENT) {
2234 atom *at1, *at2;
2235
2236 if (s2->token != SQL_IDENT)
2237 return -1;
2238 at1 = sql_bind_arg(sql, s1->data.lval->h->data.i_val);
2239 at2 = sql_bind_arg(sql, s2->data.lval->h->data.i_val);
2240 return atom_cmp(at1, at2);
2241 } else {
2242 return dlist_cmp(sql, s1->data.lval, s2->data.lval);
2243 }
2244 }
2245 case type_type:
2246 return subtype_cmp(&s1->data.typeval, &s2->data.typeval);
2247 case type_symbol:
2248 if (s1->token == SQL_SELECT) {
2249 if (s2->token != SQL_SELECT)
2250 return -1;
2251 return SelectNodeCmp(sql, (SelectNode *) s1, (SelectNode *) s2);
2252 } else if (s1->token == SQL_ATOM) {
2253 if (s2->token != SQL_ATOM)
2254 return -1;
2255 return AtomNodeCmp((AtomNode *) s1, (AtomNode *) s2);
2256 } else {
2257 return symbol_cmp(sql, s1->data.sym, s2->data.sym);
2258 }
2259 default:
2260 assert(0);
2261 }
2262 return 0; /* never reached, just to pacify compilers */
2263}
2264
2265int
2266symbol_cmp(mvc *sql, symbol *s1, symbol *s2)
2267{
2268 return _symbol_cmp(sql, s1, s2);
2269}
2270