LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_scenario.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 478 718 66.6 %
Date: 2021-10-13 02:24:04 Functions: 23 25 92.0 %

          Line data    Source code
       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 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (authors) N. Nes, M.L. Kersten
      11             :  * The SQL scenario implementation is a derivative of the MAL session scenario.
      12             :  *
      13             :  */
      14             : /*
      15             :  * Before we are can process SQL statements the global catalog
      16             :  * should be initialized. Thereafter, each time a client enters
      17             :  * we update its context descriptor to denote an SQL scenario.
      18             :  */
      19             : #include "monetdb_config.h"
      20             : #include "mal_backend.h"
      21             : #include "sql_scenario.h"
      22             : #include "sql_result.h"
      23             : #include "sql_gencode.h"
      24             : #include "sql_optimizer.h"
      25             : #include "sql_assert.h"
      26             : #include "sql_execute.h"
      27             : #include "sql_env.h"
      28             : #include "sql_mvc.h"
      29             : #include "sql_user.h"
      30             : #include "sql_datetime.h"
      31             : #include "sql_import.h"
      32             : #include "mal.h"
      33             : #include "mal_instruction.h"
      34             : #include "mal_interpreter.h"
      35             : #include "mal_parser.h"
      36             : #include "mal_builder.h"
      37             : #include "mal_namespace.h"
      38             : #include "mal_debugger.h"
      39             : #include "mal_linker.h"
      40             : #include "bat5.h"
      41             : #include "wlc.h"
      42             : #include "wlr.h"
      43             : #include "msabaoth.h"
      44             : #include "gdk_time.h"
      45             : #include "optimizer.h"
      46             : #include "opt_prelude.h"
      47             : #include "opt_pipes.h"
      48             : #include "opt_mitosis.h"
      49             : #include <unistd.h>
      50             : #include "sql_upgrades.h"
      51             : 
      52             : #define MAX_SQL_MODULES 128
      53             : static int sql_modules = 0;
      54             : static struct sql_module {
      55             :         const char *name;
      56             :         const unsigned char *code;
      57             : } sql_module[MAX_SQL_MODULES];
      58             : 
      59             : static int
      60       18746 : sql_module_compare(const void *a, const void *b)
      61             : {
      62             :         const struct sql_module *l = a, *r = b;
      63       18746 :         return strcmp(l->name, r->name);
      64             : }
      65             : 
      66             : void
      67        8956 : sql_register(const char *name, const unsigned char *code)
      68             : {
      69        8956 :         assert (sql_modules < MAX_SQL_MODULES);
      70        8956 :         sql_module[sql_modules].name = name;
      71        8956 :         sql_module[sql_modules].code = code;
      72        8956 :         sql_modules++;
      73        8956 : }
      74             : 
      75             : static sql_store SQLstore = NULL;
      76             : int SQLdebug = 0;
      77             : static const char *sqlinit = NULL;
      78             : static MT_Lock sql_contextLock = MT_LOCK_INITIALIZER(sql_contextLock);
      79             : 
      80             : static void
      81         310 : monet5_freecode(int clientid, const char *name)
      82             : {
      83             :         str msg;
      84             : 
      85         310 :         msg = SQLCacheRemove(MCgetClient(clientid), name);
      86         310 :         if (msg)
      87           8 :                 freeException(msg);     /* do something with error? */
      88         310 : }
      89             : 
      90             : static str SQLinit(Client c);
      91             : 
      92             : str
      93             : //SQLprelude(void *ret)
      94         266 : SQLprelude(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      95             : {
      96             :         str tmp;
      97         266 :         Scenario ms, s = getFreeScenario();
      98             : 
      99             :         (void) mb;
     100             :         (void) stk;
     101             :         (void) pci;
     102         266 :         if (!s)
     103           0 :                 throw(MAL, "sql.start", SQLSTATE(42000) "out of scenario slots");
     104         266 :         sqlinit = GDKgetenv("sqlinit");
     105         266 :         *s = (struct SCENARIO) {
     106             :                 .name = "S_Q_L",
     107             :                 .language = "sql",
     108             :                 .exitSystem = "SQLexit",
     109             :                 .exitSystemCmd = SQLexit,
     110             :                 .initClient = "SQLinitClient",
     111             :                 .initClientCmd = SQLinitClient,
     112             :                 .exitClient = "SQLexitClient",
     113             :                 .exitClientCmd = SQLexitClient,
     114             :                 .reader = "SQLreader",
     115             :                 .readerCmd = SQLreader,
     116             :                 .parser = "SQLparser",
     117             :                 .parserCmd = SQLparser,
     118             :                 .engine = "SQLengine",
     119             :                 .engineCmd = SQLengine,
     120             :                 .callback = "SQLcallback",
     121             :                 .callbackCmd = SQLcallback,
     122             :         };
     123         266 :         ms = getFreeScenario();
     124         266 :         if (!ms)
     125           0 :                 throw(MAL, "sql.start", SQLSTATE(42000) "out of scenario slots");
     126             : 
     127         266 :         *ms = (struct SCENARIO) {
     128             :                 .name = "M_S_Q_L",
     129             :                 .language = "msql",
     130             :                 .exitSystem = "SQLexit",
     131             :                 .exitSystemCmd = SQLexit,
     132             :                 .initClient = "SQLinitClientFromMAL",
     133             :                 .initClientCmd = SQLinitClientFromMAL,
     134             :                 .exitClient = "SQLexitClient",
     135             :                 .exitClientCmd = SQLexitClient,
     136             :                 .reader = "MALreader",
     137             :                 .readerCmd = MALreader,
     138             :                 .parser = "MALparser",
     139             :                 .parserCmd = MALparser,
     140             :                 .optimizer = "MALoptimizer",
     141             :                 .optimizerCmd = MALoptimizer,
     142             :                 .engine = "MALengine",
     143             :                 .engineCmd = MALengine,
     144             :                 .callback = "MALcallback",
     145             :                 .callbackCmd = MALcallback,
     146             :         };
     147             : 
     148         266 :         tmp = SQLinit(cntxt);
     149         266 :         if (tmp != MAL_SUCCEED) {
     150           1 :                 TRC_CRITICAL(SQL_PARSER, "Fatal error during initialization: %s\n", tmp);
     151           1 :                 if (!GDKembedded()) {
     152           1 :                         freeException(tmp);
     153           1 :                         if ((tmp = GDKerrbuf) && *tmp)
     154           0 :                                 TRC_CRITICAL(SQL_PARSER, SQLSTATE(42000) "GDK reported: %s\n", tmp);
     155           1 :                         fflush(stderr);
     156           1 :                         exit(1);
     157             :                 } else {
     158             :                         return tmp;
     159             :                 }
     160             :         }
     161         265 :         if (!GDKembedded()) {
     162         253 :                 fprintf(stdout, "# MonetDB/SQL module loaded\n");
     163         253 :                 fflush(stdout);         /* make merovingian see this *now* */
     164             :         }
     165         265 :         if (GDKinmemory(0) || GDKembedded()) {
     166          12 :                 s->name = "sql";
     167          12 :                 ms->name = "msql";
     168          12 :                 return MAL_SUCCEED;
     169             :         }
     170             :         /* only register availability of scenarios AFTER we are inited! */
     171         253 :         s->name = "sql";
     172         253 :         tmp = msab_marchScenario(s->name);
     173         253 :         if (tmp != NULL) {
     174           0 :                 char *err = createException(MAL, "sql.start", "%s", tmp);
     175           0 :                 free(tmp);
     176           0 :                 return err;
     177             :         }
     178         253 :         ms->name = "msql";
     179         253 :         tmp = msab_marchScenario(ms->name);
     180         253 :         if (tmp != NULL) {
     181           0 :                 char *err = createException(MAL, "sql.start", "%s", tmp);
     182           0 :                 free(tmp);
     183           0 :                 return err;
     184             :         }
     185             :         return MAL_SUCCEED;
     186             : }
     187             : 
     188             : str
     189         264 : SQLexit(Client c)
     190             : {
     191             :         (void) c;               /* not used */
     192         264 :         MT_lock_set(&sql_contextLock);
     193         264 :         if (SQLstore) {
     194         264 :                 mvc_exit(SQLstore);
     195         264 :                 SQLstore = NULL;
     196             :         }
     197         264 :         MT_lock_unset(&sql_contextLock);
     198         264 :         return MAL_SUCCEED;
     199             : }
     200             : 
     201             : str
     202         264 : SQLepilogue(void *ret)
     203             : {
     204             :         char *s = "sql", *m = "msql";
     205             :         str res;
     206             : 
     207             :         (void) ret;
     208         264 :         (void) SQLexit(NULL);
     209             :         /* this function is never called, but for the style of it, we clean
     210             :          * up our own mess */
     211         264 :         if (!GDKinmemory(0) && !GDKembedded()) {
     212         253 :                 res = msab_retreatScenario(m);
     213         253 :                 if (!res)
     214         253 :                         res = msab_retreatScenario(s);
     215         253 :                 if (res != NULL) {
     216           0 :                         char *err = createException(MAL, "sql.start", "%s", res);
     217           0 :                         free(res);
     218           0 :                         return err;
     219             :                 }
     220             :         }
     221             :         /* return scenarios */
     222         264 :         Scenario sc = findScenario(s);
     223         264 :         if (sc)
     224         264 :                 sc->name = NULL;
     225         264 :         sc = findScenario(m);
     226         264 :         if (sc)
     227         264 :                 sc->name = NULL;
     228             :         return MAL_SUCCEED;
     229             : }
     230             : 
     231             : static char*
     232        5317 : SQLprepareClient(Client c, int login)
     233             : {
     234             :         mvc *m = NULL;
     235             :         backend *be = NULL;
     236             :         str msg = MAL_SUCCEED;
     237             : 
     238        5317 :         if (c->sqlcontext == 0) {
     239        5317 :                 sql_allocator *sa = sa_create(NULL);
     240        5317 :                 if (sa == NULL) {
     241           0 :                         msg = createException(SQL,"sql.initClient", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     242           0 :                         goto bailout;
     243             :                 }
     244        5317 :                 m = mvc_create(SQLstore, sa, c->idx, SQLdebug, c->fdin, c->fdout);
     245        5317 :                 if (m == NULL) {
     246           0 :                         msg = createException(SQL,"sql.initClient", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     247           0 :                         goto bailout;
     248             :                 }
     249        5317 :                 if (c->scenario && strcmp(c->scenario, "msql") == 0)
     250         127 :                         m->reply_size = -1;
     251        5317 :                 be = (void *) backend_create(m, c);
     252        5317 :                 if ( be == NULL) {
     253           0 :                         mvc_destroy(m);
     254           0 :                         msg = createException(SQL,"sql.initClient", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     255           0 :                         goto bailout;
     256             :                 }
     257             :         } else {
     258           0 :                 assert(0);
     259             : #if 0
     260             :                 be = c->sqlcontext;
     261             :                 m = be->mvc;
     262             :                 /* Only reset if there is no active transaction which
     263             :                  * can happen when we combine sql.init with msql.
     264             :                 */
     265             :                 if (m->session->tr->active)
     266             :                         return NULL;
     267             :                 if (mvc_reset(m, c->fdin, c->fdout, SQLdebug) < 0) {
     268             :                         msg = createException(SQL,"sql.initClient", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     269             :                         goto bailout;
     270             :                 }
     271             :                 backend_reset(be);
     272             : #endif
     273             :         }
     274        5317 :         MT_lock_unset(&sql_contextLock);
     275        5317 :         if (login) {
     276        5052 :                 switch (monet5_user_set_def_schema(m, c->user)) {
     277           0 :                         case -1:
     278           0 :                                 msg = createException(SQL,"sql.initClient", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     279           0 :                                 goto bailout;
     280           1 :                         case -2:
     281           1 :                                 msg = createException(SQL,"sql.initClient", SQLSTATE(42000) "The user was not found in the database, this session is going to terminate");
     282           1 :                                 goto bailout;
     283           0 :                         case -3:
     284           0 :                                 msg = createException(SQL,"sql.initClient", SQLSTATE(42000) "The user's default schema was not found, this session is going to terminate");
     285           0 :                                 goto bailout;
     286             :                         default:
     287             :                                 break;
     288             :                 }
     289         265 :         }
     290             : 
     291        5316 :         if (c->handshake_options) {
     292        1502 :                 char *strtok_state = NULL;
     293        1502 :                 char *tok = strtok_r(c->handshake_options, ",", &strtok_state);
     294        8524 :                 while (tok != NULL) {
     295             :                         int value;
     296        7022 :                         if (sscanf(tok, "auto_commit=%d", &value) == 1) {
     297        1340 :                                 bool auto_commit= value != 0;
     298        1340 :                                 m->session->auto_commit = auto_commit;
     299        1340 :                                 m->session->ac_on_commit = auto_commit;
     300        5682 :                         } else if (sscanf(tok, "reply_size=%d", &value) == 1) {
     301        1501 :                                 if (value < -1) {
     302           0 :                                         msg = createException(SQL, "SQLprepareClient", SQLSTATE(42000) "Reply_size cannot be negative");
     303           0 :                                         goto bailout;
     304             :                                 }
     305        1501 :                                 m->reply_size = value;
     306        4181 :                         } else if (sscanf(tok, "size_header=%d", &value) == 1) {
     307        1340 :                                         be->sizeheader = value != 0;
     308        2841 :                         } else if (sscanf(tok, "columnar_protocol=%d", &value) == 1) {
     309        2680 :                                 c->protocol = (value != 0) ? PROTOCOL_COLUMNAR : PROTOCOL_9;
     310        1501 :                         } else if (sscanf(tok, "time_zone=%d", &value) == 1) {
     311        1501 :                                 sql_schema *s = mvc_bind_schema(m, "sys");
     312        1501 :                                 sql_var *var = find_global_var(m, s, "current_timezone");
     313             :                                 ValRecord val;
     314        1501 :                                 VALinit(&val, TYPE_lng, &(lng){1000 * value});
     315        1501 :                                 sql_update_var(m, s, "current_timezone", &val);
     316        1501 :                                 sqlvar_set(var, &val);
     317             :                         } else {
     318           0 :                                 msg = createException(SQL, "SQLprepareClient", SQLSTATE(42000) "unexpected handshake option: %s", tok);
     319           0 :                                 goto bailout;
     320             :                         }
     321             : 
     322        7022 :                         tok = strtok_r(NULL, ",", &strtok_state);
     323             :                 }
     324             :         }
     325             : 
     326             : 
     327        3814 : bailout:
     328        5317 :         MT_lock_set(&sql_contextLock);
     329             :         /* expect SQL text first */
     330        5317 :         if (be)
     331        5317 :                 be->language = 'S';
     332             :         /* Set state, this indicates an initialized client scenario */
     333        5317 :         c->state[MAL_SCENARIO_READER] = c;
     334        5317 :         c->state[MAL_SCENARIO_PARSER] = c;
     335        5317 :         c->state[MAL_SCENARIO_OPTIMIZE] = c;
     336        5317 :         c->sqlcontext = be;
     337        5317 :         if (msg)
     338           1 :                 c->mode = FINISHCLIENT;
     339        5317 :         return msg;
     340             : }
     341             : 
     342             : str
     343        5317 : SQLresetClient(Client c)
     344             : {
     345             :         str msg = MAL_SUCCEED, other = MAL_SUCCEED;
     346             : 
     347        5317 :         if (c->sqlcontext == NULL)
     348           0 :                 throw(SQL, "SQLexitClient", SQLSTATE(42000) "MVC catalogue not available");
     349             :         if (c->sqlcontext) {
     350             :                 sql_allocator *pa = NULL;
     351             :                 backend *be = c->sqlcontext;
     352        5317 :                 mvc *m = be->mvc;
     353             : 
     354        5317 :                 assert(m->session);
     355        5317 :                 if (m->session->auto_commit && m->session->tr->active) {
     356          11 :                         if (mvc_status(m) >= 0)
     357          11 :                                 msg = mvc_commit(m, 0, NULL, false);
     358             :                 }
     359        5317 :                 if (m->session->tr->active)
     360        1016 :                         other = mvc_rollback(m, 0, NULL, false);
     361             : 
     362        5317 :                 res_tables_destroy(be->results);
     363        5317 :                 be->results = NULL;
     364             : 
     365        5317 :                 pa = m->pa;
     366        5317 :                 mvc_destroy(m);
     367        5317 :                 backend_destroy(be);
     368        5317 :                 c->state[MAL_SCENARIO_OPTIMIZE] = NULL;
     369        5317 :                 c->state[MAL_SCENARIO_PARSER] = NULL;
     370        5317 :                 c->sqlcontext = NULL;
     371        5317 :                 sa_destroy(pa);
     372             :         }
     373        5317 :         c->state[MAL_SCENARIO_READER] = NULL;
     374        5317 :         if (other && !msg)
     375             :                 msg = other;
     376        5317 :         else if (other && msg)
     377           0 :                 freeException(other);
     378             :         return msg;
     379             : }
     380             : 
     381             : MT_Id sqllogthread;
     382             : 
     383             : static str
     384         266 : SQLinit(Client c)
     385             : {
     386         266 :         const char *debug_str = GDKgetenv("sql_debug");
     387             :         char *msg = MAL_SUCCEED, *other = MAL_SUCCEED;
     388         266 :         bool readonly = GDKgetenv_isyes("gdk_readonly");
     389         266 :         bool single_user = GDKgetenv_isyes("gdk_single_user");
     390             :         static int maybeupgrade = 1;
     391             :         backend *be = NULL;
     392             :         mvc *m = NULL;
     393             :         const char *opt_pipe;
     394             : 
     395         266 :         if ((opt_pipe = GDKgetenv("sql_optimizer")) && !isOptimizerPipe(opt_pipe))
     396           0 :                 throw(SQL, "sql.init", SQLSTATE(42000) "invalid sql optimizer pipeline %s", opt_pipe);
     397             : 
     398         266 :         MT_lock_set(&sql_contextLock);
     399             : 
     400         266 :         if (SQLstore) {
     401           0 :                 MT_lock_unset(&sql_contextLock);
     402           0 :                 return MAL_SUCCEED;
     403             :         }
     404             : 
     405         266 :         be_funcs.fcode = &monet5_freecode,
     406         266 :         be_funcs.fresolve_function = &monet5_resolve_function,
     407         266 :         be_funcs.fhas_module_function = &monet5_has_module,
     408         266 :         monet5_user_init(&be_funcs);
     409             : 
     410         266 :         if (debug_str)
     411         266 :                 SQLdebug = strtol(debug_str, NULL, 10);
     412         266 :         if (single_user)
     413           0 :                 SQLdebug |= 64;
     414         266 :         if (readonly)
     415           4 :                 SQLdebug |= 32;
     416             : 
     417         531 :         if ((SQLstore = mvc_init(SQLdebug, GDKinmemory(0) ? store_mem : store_bat, readonly, single_user)) == NULL) {
     418           1 :                 MT_lock_unset(&sql_contextLock);
     419           1 :                 throw(SQL, "SQLinit", SQLSTATE(42000) "Catalogue initialization failed");
     420             :         }
     421         265 :         sqlinit = GDKgetenv("sqlinit");
     422         265 :         if (sqlinit) {          /* add sqlinit to the fdin stack */
     423           0 :                 buffer *b = (buffer *) GDKmalloc(sizeof(buffer));
     424           0 :                 size_t len = strlen(sqlinit);
     425           0 :                 char* cbuf = _STRDUP(sqlinit);
     426             :                 stream *buf;
     427             :                 bstream *fdin;
     428             : 
     429           0 :                 if ( b == NULL || cbuf == NULL) {
     430           0 :                         mvc_exit(SQLstore);
     431           0 :                         SQLstore = NULL;
     432           0 :                         MT_lock_unset(&sql_contextLock);
     433           0 :                         GDKfree(b);
     434           0 :                         GDKfree(cbuf);
     435           0 :                         throw(SQL,"sql.init",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     436             :                 }
     437             : 
     438           0 :                 buffer_init(b, cbuf, len);
     439           0 :                 buf = buffer_rastream(b, "si");
     440           0 :                 if ( buf == NULL) {
     441           0 :                         mvc_exit(SQLstore);
     442           0 :                         SQLstore = NULL;
     443           0 :                         MT_lock_unset(&sql_contextLock);
     444           0 :                         buffer_destroy(b);
     445           0 :                         throw(SQL,"sql.init",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     446             :                 }
     447             : 
     448           0 :                 fdin = bstream_create(buf, b->len);
     449           0 :                 if ( fdin == NULL) {
     450           0 :                         mvc_exit(SQLstore);
     451           0 :                         SQLstore = NULL;
     452           0 :                         MT_lock_unset(&sql_contextLock);
     453           0 :                         buffer_destroy(b);
     454           0 :                         throw(SQL,"sql.init",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     455             :                 }
     456             : 
     457           0 :                 bstream_next(fdin);
     458           0 :                 if ( MCpushClientInput(c, fdin, 0, "") < 0)
     459           0 :                         TRC_ERROR(SQL_PARSER, "Could not switch client input stream\n");
     460             :         }
     461         265 :         if ((msg = SQLprepareClient(c, 0)) != NULL) {
     462           0 :                 mvc_exit(SQLstore);
     463           0 :                 SQLstore = NULL;
     464           0 :                 MT_lock_unset(&sql_contextLock);
     465           0 :                 TRC_INFO(SQL_PARSER, "%s\n", msg);
     466           0 :                 return msg;
     467             :         }
     468         265 :         be = c->sqlcontext;
     469         265 :         m = be->mvc;
     470             :         /* initialize the database with predefined SQL functions */
     471         265 :         sqlstore *store = SQLstore;
     472         265 :         if (store->first == 0) {
     473             :                 /* check whether table sys.systemfunctions exists: if
     474             :                  * it doesn't, this is probably a restart of the
     475             :                  * server after an incomplete initialization */
     476          79 :                 if ((msg = SQLtrans(m)) == MAL_SUCCEED) {
     477          79 :                         sql_schema *s = mvc_bind_schema(m, "sys");
     478          79 :                         sql_table *t = s ? mvc_bind_table(m, s, "systemfunctions") : NULL;
     479          79 :                         if (t == NULL)
     480           0 :                                 store->first = 1;
     481          79 :                         msg = mvc_rollback(m, 0, NULL, false);
     482             :                 }
     483          79 :                 if (msg) {
     484           0 :                         freeException(msg);
     485             :                         msg = MAL_SUCCEED;
     486             :                 }
     487             :         }
     488         265 :         if (store->first > 0) {
     489         186 :                 store->first = 0;
     490         186 :                 maybeupgrade = 0;
     491             : 
     492         186 :                 qsort(sql_module, sql_modules, sizeof(sql_module[0]), sql_module_compare);
     493        6692 :                 for (int i = 0; i < sql_modules && !msg; i++) {
     494        6506 :                         const char *createdb_inline = (const char*)sql_module[i].code;
     495             : 
     496        6506 :                         msg = SQLstatementIntern(c, createdb_inline, "sql.init", TRUE, FALSE, NULL);
     497        6506 :                         if (m->sa)
     498           0 :                                 sa_destroy(m->sa);
     499        6506 :                         m->sa = NULL;
     500             :                 }
     501             :                 /* 99_system.sql */
     502         186 :                 if (!msg) {
     503             :                         const char *createdb_inline = " \
     504             :                                 create trigger system_update_schemas after update on sys.schemas for each statement call sys_update_schemas(); \
     505             :                                 create trigger system_update_tables after update on sys._tables for each statement call sys_update_tables(); \
     506             :                                 update sys.functions set system = true; \
     507             :                                 create view sys.systemfunctions as select id as function_id from sys.functions where system; \
     508             :                                 grant select on sys.systemfunctions to public; \
     509             :                                 update sys._tables set system = true; \
     510             :                                 update sys.schemas set system = true; \
     511             :                                 UPDATE sys.types     SET schema_id = (SELECT id FROM sys.schemas WHERE name = 'sys') WHERE schema_id = 0 AND schema_id NOT IN (SELECT id from sys.schemas); \
     512             :                                 UPDATE sys.functions SET schema_id = (SELECT id FROM sys.schemas WHERE name = 'sys') WHERE schema_id = 0 AND schema_id NOT IN (SELECT id from sys.schemas); \
     513             :                                 ";
     514         186 :                         msg = SQLstatementIntern(c, createdb_inline, "sql.init", TRUE, FALSE, NULL);
     515         186 :                         if (m->sa)
     516           0 :                                 sa_destroy(m->sa);
     517         186 :                         m->sa = NULL;
     518             :                 }
     519             :                 /* Commit after all the startup scripts have been processed */
     520         186 :                 assert(m->session->tr->active);
     521         186 :                 if (mvc_status(m) < 0 || msg)
     522           0 :                         other = mvc_rollback(m, 0, NULL, false);
     523             :                 else
     524         186 :                         other = mvc_commit(m, 0, NULL, false);
     525             : 
     526         186 :                 if (other && !msg) /* 'msg' variable might be set or not, as well as 'other'. Throw the earliest one */
     527             :                         msg = other;
     528         186 :                 else if (other)
     529           0 :                         freeException(other);
     530         186 :                 if (msg)
     531           0 :                         TRC_INFO(SQL_PARSER, "%s\n", msg);
     532             :         } else {                /* handle upgrades */
     533          79 :                 if (!m->sa)
     534          79 :                         m->sa = sa_create(m->pa);
     535          79 :                 if (!m->sa) {
     536           0 :                         msg = createException(MAL, "createdb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     537          79 :                 } else if (maybeupgrade) {
     538          69 :                         if ((msg = SQLtrans(m)) == MAL_SUCCEED) {
     539          69 :                                 int res = SQLupgrades(c, m);
     540             :                                 /* Commit at the end of the upgrade */
     541          69 :                                 assert(m->session->tr->active);
     542          69 :                                 if (mvc_status(m) < 0 || res)
     543           0 :                                         msg = mvc_rollback(m, 0, NULL, false);
     544             :                                 else
     545          69 :                                         msg = mvc_commit(m, 0, NULL, false);
     546             :                         }
     547             :                 }
     548          79 :                 maybeupgrade = 0;
     549             :         }
     550         265 :         fflush(stdout);
     551         265 :         fflush(stderr);
     552             : 
     553             :         /* send error from create scripts back to the first client */
     554         265 :         if (msg) {
     555           0 :                 msg = handle_error(m, 0, msg);
     556           0 :                 *m->errstr = 0;
     557           0 :                 sqlcleanup(be, mvc_status(m));
     558             :         }
     559             : 
     560         265 :         other = SQLresetClient(c);
     561         265 :         if (other && !msg) /* 'msg' variable might be set or not, as well as 'other'. Throw the earliest one */
     562             :                 msg = other;
     563         265 :         else if (other)
     564           0 :                 freeException(other);
     565         265 :         if (msg != MAL_SUCCEED) {
     566           0 :                 mvc_exit(SQLstore);
     567           0 :                 SQLstore = NULL;
     568           0 :                 MT_lock_unset(&sql_contextLock);
     569           0 :                 return msg;
     570             :         }
     571             : 
     572         265 :         if (GDKinmemory(0)) {
     573           1 :                 MT_lock_unset(&sql_contextLock);
     574           1 :                 return msg;
     575             :         }
     576             : 
     577         264 :         if ((sqllogthread = THRcreate((void (*)(void *)) mvc_logmanager, SQLstore, MT_THR_DETACHED, "logmanager")) == 0) {
     578           0 :                 mvc_exit(SQLstore);
     579           0 :                 SQLstore = NULL;
     580           0 :                 MT_lock_unset(&sql_contextLock);
     581           0 :                 throw(SQL, "SQLinit", SQLSTATE(42000) "Starting log manager failed");
     582             :         }
     583         264 :         if (wlc_state == WLC_STARTUP && GDKgetenv_istrue("wlc_enabled") && (msg = WLCinit()) != MAL_SUCCEED) {
     584           0 :                 mvc_exit(SQLstore);
     585           0 :                 SQLstore = NULL;
     586           0 :                 MT_lock_unset(&sql_contextLock);
     587           0 :                 return msg;
     588             :         }
     589             : 
     590         264 :         MT_lock_unset(&sql_contextLock);
     591         264 :         return MAL_SUCCEED;
     592             : }
     593             : 
     594             : #define TRANS_ABORTED SQLSTATE(25005) "Current transaction is aborted (please ROLLBACK)\n"
     595             : 
     596             : str
     597        2665 : handle_error(mvc *m, int pstatus, str msg)
     598             : {
     599             :         str new = NULL, newmsg = MAL_SUCCEED;
     600             : 
     601             :         /* transaction already broken */
     602        2665 :         if (m->type != Q_TRANS && pstatus < 0) {
     603         592 :                 freeException(msg);
     604         592 :                 return createException(SQL,"sql.execute",TRANS_ABORTED);
     605        2073 :         } else if ( GDKerrbuf && GDKerrbuf[0]){
     606           0 :                 new = GDKstrdup(GDKerrbuf);
     607           0 :                 GDKerrbuf[0] = 0;
     608        2073 :         } else if ( *m->errstr){
     609           0 :                 new = GDKstrdup(m->errstr);
     610           0 :                 m->errstr[0] = 0;
     611             :         }
     612        2073 :         if ( new && msg){
     613           0 :                 newmsg = concatErrors(msg, new);
     614           0 :                 GDKfree(new);
     615        2073 :         } else if (msg)
     616             :                 newmsg = msg;
     617           0 :         else if (new) {
     618           0 :                 newmsg = createException(SQL, "sql.execute", "%s", new);
     619           0 :                 GDKfree(new);
     620             :         }
     621             :         return newmsg;
     622             : }
     623             : 
     624             : str
     625      136585 : SQLautocommit(mvc *m)
     626             : {
     627             :         str msg = MAL_SUCCEED;
     628             : 
     629      136585 :         if (m->session->auto_commit && m->session->tr->active) {
     630       70794 :                 if (mvc_status(m) < 0) {
     631        4374 :                         msg = mvc_rollback(m, 0, NULL, false);
     632             :                 } else {
     633       66420 :                         msg = mvc_commit(m, 0, NULL, false);
     634             :                 }
     635             :         }
     636      136585 :         return msg;
     637             : }
     638             : 
     639             : str
     640      157759 : SQLtrans(mvc *m)
     641             : {
     642      157759 :         if (!m->session->tr->active) {
     643             :                 sql_session *s;
     644             : 
     645       73501 :                 switch (mvc_trans(m)) {
     646           0 :                         case -1:
     647           0 :                                 throw(SQL, "sql.trans", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     648           4 :                         case -3:
     649           4 :                                 throw(SQL, "sql.trans", SQLSTATE(42000) "The session's schema was not found, this transaction won't start");
     650             :                         default:
     651             :                                 break;
     652             :                 }
     653       73497 :                 s = m->session;
     654       73497 :                 if (!s->schema) {
     655           0 :                         switch (monet5_user_get_def_schema(m, m->user_id, &s->schema_name)) {
     656           0 :                                 case -1:
     657           0 :                                         mvc_cancel_session(m);
     658           0 :                                         throw(SQL, "sql.trans", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     659           0 :                                 case -2:
     660           0 :                                         mvc_cancel_session(m);
     661           0 :                                         throw(SQL, "sql.trans", SQLSTATE(42000) "The user was not found in the database, this session is going to terminate");
     662           0 :                                 case -3:
     663           0 :                                         mvc_cancel_session(m);
     664           0 :                                         throw(SQL, "sql.trans", SQLSTATE(42000) "The user's default schema was not found, this session is going to terminate");
     665             :                                 default:
     666             :                                         break;
     667             :                         }
     668           0 :                         if (!(s->schema = find_sql_schema(s->tr, s->schema_name))) {
     669           0 :                                 mvc_cancel_session(m);
     670           0 :                                 throw(SQL, "sql.trans", SQLSTATE(42000) "The session's schema was not found, this session is going to terminate");
     671             :                         }
     672             :                 }
     673             :         }
     674             :         return MAL_SUCCEED;
     675             : }
     676             : 
     677             : str
     678        5052 : SQLinitClient(Client c)
     679             : {
     680             :         str msg = MAL_SUCCEED;
     681             : 
     682        5052 :         MT_lock_set(&sql_contextLock);
     683        5052 :         if (!SQLstore) {
     684           0 :                 MT_lock_unset(&sql_contextLock);
     685           0 :                 throw(SQL, "SQLinitClient", SQLSTATE(42000) "Catalogue not available");
     686             :         }
     687        5052 :         msg = SQLprepareClient(c, true);
     688        5052 :         MT_lock_unset(&sql_contextLock);
     689        5052 :         return msg;
     690             : }
     691             : 
     692             : str
     693         127 : SQLinitClientFromMAL(Client c)
     694             : {
     695             :         str msg = MAL_SUCCEED;
     696             : 
     697         127 :         if ((msg = SQLinitClient(c)) != MAL_SUCCEED) {
     698           0 :                 c->mode = FINISHCLIENT;
     699           0 :                 return msg;
     700             :         }
     701             : 
     702         127 :         mvc* m = ((backend*) c->sqlcontext)->mvc;
     703             : 
     704             :         /* Crucial step:
     705             :          * MAL scripts that interact with the sql module
     706             :          * must have a properly initialized transaction.
     707             :          */
     708         127 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED) {
     709           0 :                 c->mode = FINISHCLIENT;
     710           0 :                 return msg;
     711             :         }
     712             :         return msg;
     713             : }
     714             : 
     715             : str
     716        5043 : SQLexitClient(Client c)
     717             : {
     718             :         str err;
     719             : 
     720        5043 :         MT_lock_set(&sql_contextLock);
     721        5043 :         if (!SQLstore) {
     722           0 :                 MT_lock_unset(&sql_contextLock);
     723           0 :                 throw(SQL, "SQLexitClient", SQLSTATE(42000) "Catalogue not available");
     724             :         }
     725        5043 :         err = SQLresetClient(c);
     726        5043 :         MT_lock_unset(&sql_contextLock);
     727        5043 :         if (err != MAL_SUCCEED)
     728             :                 return err;
     729        5043 :         MALexitClient(c);
     730        5043 :         return MAL_SUCCEED;
     731             : }
     732             : 
     733             : str
     734           9 : SQLstatement(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     735             : {
     736           9 :         const char *expr = *getArgReference_str(stk, pci, 1);
     737             : 
     738             :         (void) mb;
     739             : 
     740           9 :         protocol_version backup = cntxt->protocol;
     741             : 
     742           9 :         if (pci->argc == 3 && *getArgReference_bit(stk, pci, 2))
     743           1 :                 cntxt->protocol = PROTOCOL_COLUMNAR;
     744             : 
     745           9 :         str msg = SQLstatementIntern(cntxt, expr, "SQLstatement", TRUE, TRUE, NULL);
     746             : 
     747           9 :         cntxt->protocol = backup;
     748             : 
     749           9 :         return msg;
     750             : }
     751             : 
     752             : str
     753           0 : SQLcompile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     754             : {
     755           0 :         str *ret = getArgReference_str(stk, pci, 0);
     756           0 :         str *expr = getArgReference_str(stk, pci, 1);
     757             :         str msg;
     758             : 
     759             :         (void) mb;
     760           0 :         *ret = NULL;
     761           0 :         if ((msg = SQLstatementIntern(cntxt, *expr, "SQLcompile", FALSE, FALSE, NULL)) != MAL_SUCCEED)
     762             :                 return msg;
     763           0 :         if ((*ret = _STRDUP("SQLcompile")) == NULL)
     764           0 :                 throw(SQL,"sql.compile",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     765             :         return MAL_SUCCEED;
     766             : }
     767             : 
     768             : /*
     769             :  * Locate a file with SQL commands and execute it. For the time being a 1MB
     770             :  * file limit is implicitly imposed. If the file can not be located in the
     771             :  * script library, we assume it is sufficiently self descriptive.
     772             :  * (Respecting the file system context where the call is executed )
     773             :  */
     774             : str
     775           0 : SQLinclude(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     776             : {
     777             :         stream *fd;
     778             :         bstream *bfd;
     779           0 :         str *name = getArgReference_str(stk, pci, 1);
     780             :         str msg = MAL_SUCCEED, fullname;
     781             :         mvc *m;
     782             :         size_t sz;
     783             : 
     784           0 :         fullname = MSP_locate_sqlscript(*name, 0);
     785           0 :         if (fullname == NULL)
     786           0 :                 fullname = *name;
     787           0 :         fd = open_rastream(fullname);
     788           0 :         if (mnstr_errnr(fd) == MNSTR_OPEN_ERROR) {
     789           0 :                 close_stream(fd);
     790           0 :                 throw(MAL, "sql.include", SQLSTATE(42000) "%s\n", mnstr_peek_error(NULL));
     791             :         }
     792           0 :         sz = getFileSize(fd);
     793           0 :         if (sz > (size_t) 1 << 29) {
     794           0 :                 close_stream(fd);
     795           0 :                 throw(MAL, "sql.include", SQLSTATE(42000) "file %s too large to process", fullname);
     796             :         }
     797           0 :         if ((bfd = bstream_create(fd, sz == 0 ? (size_t) (128 * BLOCK) : sz)) == NULL) {
     798           0 :                 close_stream(fd);
     799           0 :                 throw(MAL, "sql.include", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     800             :         }
     801           0 :         if (bstream_next(bfd) < 0) {
     802           0 :                 bstream_destroy(bfd);
     803           0 :                 throw(MAL, "sql.include", SQLSTATE(42000) "could not read %s\n", *name);
     804             :         }
     805             : 
     806           0 :         msg = SQLstatementIntern(cntxt, bfd->buf, "sql.include", TRUE, FALSE, NULL);
     807           0 :         bstream_destroy(bfd);
     808           0 :         m = ((backend *) cntxt->sqlcontext)->mvc;
     809           0 :         if (m->sa)
     810           0 :                 sa_destroy(m->sa);
     811           0 :         m->sa = NULL;
     812             :         (void) mb;
     813           0 :         return msg;
     814             : }
     815             : 
     816             : /*
     817             :  * The SQL reader collects a (sequence) of statements from the input
     818             :  * stream, but only when no unresolved 'nxt' character is visible.
     819             :  * In combination with SQLparser this ensures that all statements
     820             :  * are handled one by one.
     821             :  *
     822             :  * The SQLreader is called from two places: the SQL parser and
     823             :  * the MAL debugger.
     824             :  * The former only occurs during the parsing phase and the
     825             :  * second only during exection.
     826             :  * This means we can safely change the language setting for
     827             :  * the duration of these calls.
     828             :  */
     829             : 
     830             : str
     831      175479 : SQLreader(Client c)
     832             : {
     833             :         bool go = true;
     834             :         str msg = MAL_SUCCEED;
     835             :         bool more = true;
     836             :         bool commit_done = false;
     837      175479 :         backend *be = (backend *) c->sqlcontext;
     838      175479 :         bstream *in = c->fdin;
     839             :         int language = -1;
     840             :         mvc *m = NULL;
     841      175479 :         bool blocked = isa_block_stream(in->s);
     842             : 
     843      175479 :         if (!SQLstore || !be || c->mode <= FINISHCLIENT) {
     844           0 :                 c->mode = FINISHCLIENT;
     845           0 :                 return MAL_SUCCEED;
     846             :         }
     847      175479 :         language = be->language;     /* 'S' for SQL, 'D' from debugger */
     848      175479 :         m = be->mvc;
     849      175479 :         m->errstr[0] = 0;
     850             :         /*
     851             :          * Continue processing any left-over input from the previous round.
     852             :          */
     853             : 
     854      372106 :         while (more) {
     855             :                 more = false;
     856             : 
     857             :                 /* Different kinds of supported statements sequences
     858             :                    A;   -- single line                  s
     859             :                    A \n B;      -- multi line                   S
     860             :                    A; B;   -- compound single block     s
     861             :                    A;   -- many multi line
     862             :                    B \n C; -- statements in one block   S
     863             :                  */
     864             :                 /* auto_commit on end of statement */
     865      201519 :                 if (language != 'D' && m->scanner.mode == LINE_N && !commit_done) {
     866       21246 :                         msg = SQLautocommit(m);
     867       21246 :                         if (msg)
     868             :                                 break;
     869             :                         commit_done = true;
     870             :                 }
     871      201519 :                 if (m->session->tr && m->session->tr->active)
     872      148947 :                         c->idle = 0;
     873             : 
     874      201519 :                 if (go && in->pos >= in->len) {
     875             :                         ssize_t rd;
     876             : 
     877      162393 :                         if (c->bak) {
     878           0 :                                 in = c->fdin;
     879           0 :                                 blocked = isa_block_stream(in->s);
     880           0 :                                 m->scanner.rs = c->fdin;
     881           0 :                                 c->fdin->pos += c->yycur;
     882           0 :                                 c->yycur = 0;
     883             :                         }
     884      162393 :                         if (in->eof || !blocked) {
     885      136353 :                                 if (language != 'D')
     886             :                                         language = 0;
     887             : 
     888             :                                 /* The rules of auto_commit require us to finish
     889             :                                    and start a transaction on the start of a new statement (s A;B; case) */
     890      136353 :                                 if (language != 'D' && !(m->emod & mod_debug) && !commit_done) {
     891      115157 :                                         msg = SQLautocommit(m);
     892      115157 :                                         if (msg)
     893             :                                                 break;
     894             :                                         commit_done = true;
     895             :                                 }
     896             : 
     897      136348 :                                 if (go && ((!blocked && mnstr_write(c->fdout, c->prompt, c->promptlength, 1) != 1) || mnstr_flush(c->fdout, MNSTR_FLUSH_DATA))) {
     898             :                                         go = false;
     899             :                                         break;
     900             :                                 }
     901      136348 :                                 in->eof = false;
     902             :                         }
     903      162388 :                         if (in->buf == NULL) {
     904             :                                 more = false;
     905             :                                 go = false;
     906      162388 :                         } else if (go && (rd = bstream_next(in)) <= 0) {
     907       30927 :                                 if (be->language == 'D' && !in->eof) {
     908           0 :                                         in->pos++;// skip 's' or 'S'
     909           0 :                                         return msg;
     910             :                                 }
     911             : 
     912       30927 :                                 if (rd == 0 && language !=0 && in->eof) {
     913             :                                         /* we hadn't seen the EOF before, so just try again
     914             :                                            (this time with prompt) */
     915             :                                         more = true;
     916       26040 :                                         continue;
     917             :                                 }
     918             :                                 go = false;
     919             :                                 break;
     920      131461 :                         } else if (go && language == 0) {
     921      131461 :                                 if (in->buf[in->pos] == 's' && !in->eof) {
     922      105497 :                                         while ((rd = bstream_next(in)) > 0)
     923             :                                                 ;
     924             :                                 }
     925      131461 :                                 be->language = in->buf[in->pos++];
     926      131461 :                                 if (be->language == 's') {
     927      105400 :                                         be->language = 'S';
     928      105400 :                                         m->scanner.mode = LINE_1;
     929       26061 :                                 } else if (be->language == 'S') {
     930        5603 :                                         m->scanner.mode = LINE_N;
     931             :                                 }
     932           0 :                         } else if (go && language == 'D' && !in->eof) {
     933           0 :                                 in->pos++;// skip 's' or 'S'
     934             :                         }
     935             :                 }
     936             :         }
     937      175479 :         if ( (c->sessiontimeout && (GDKusec() - c->session) > c->sessiontimeout) || !go || (strncmp(CURRENT(c), "\\q", 2) == 0)) {
     938        4887 :                 in->pos = in->len;        /* skip rest of the input */
     939        4887 :                 c->mode = FINISHCLIENT;
     940        4887 :                 return msg;
     941             :         }
     942             :         return msg;
     943             : }
     944             : 
     945             : /*
     946             :  * The SQL block is stored in the client input buffer, from which it
     947             :  * can be parsed by the SQL parser. The client structure contains
     948             :  * a small table of bounded tables. This should be reset before we
     949             :  * parse a new statement sequence.
     950             :  * Before we parse the sql statement, we look for any variable settings
     951             :  * for specific commands.
     952             :  * The most important one is to prepare code to be handled by the debugger.
     953             :  * The current analysis is simple and fulfills our short-term needs.
     954             :  * A future version may analyze the parameter settings in more detail.
     955             :  */
     956             : 
     957             : #define MAX_QUERY       (64*1024*1024)
     958             : 
     959             : str
     960      170587 : SQLparser(Client c)
     961             : {
     962      170587 :         bstream *in = c->fdin;
     963      170587 :         stream *out = c->fdout;
     964      170587 :         str msg = NULL;
     965             :         backend *be;
     966             :         mvc *m;
     967             :         int oldvtop, oldstop, oldvid, ok;
     968      170587 :         int pstatus = 0;
     969             :         int err = 0, opt, preparedid = -1;
     970             : 
     971      170587 :         c->query = NULL;
     972      170587 :         be = (backend *) c->sqlcontext;
     973      170587 :         if (be == 0) {
     974             :                 /* leave a message in the log */
     975           0 :                 TRC_ERROR(SQL_PARSER, "SQL state description is missing, cannot handle client!\n");
     976             :                 /* stop here, instead of printing the exception below to the
     977             :                  * client in an endless loop */
     978           0 :                 c->mode = FINISHCLIENT;
     979           0 :                 throw(SQL, "SQLparser", SQLSTATE(42000) "State descriptor missing, aborting");
     980             :         }
     981      170587 :         oldvid = c->curprg->def->vid;
     982      170587 :         oldvtop = c->curprg->def->vtop;
     983      170587 :         oldstop = c->curprg->def->stop;
     984      170587 :         be->vtop = oldvtop;
     985      170587 :         be->vid = oldvid;
     986             : 
     987      170587 :         m = be->mvc;
     988      170587 :         m->type = Q_PARSE;
     989      170587 :         if (be->language != 'X') {
     990      150129 :                 if ((msg = SQLtrans(m)) != MAL_SUCCEED) {
     991           4 :                         c->mode = FINISHCLIENT;
     992           4 :                         return msg;
     993             :                 }
     994             :         }
     995      170583 :         pstatus = m->session->status;
     996             : 
     997             :         /* sqlparse needs sql allocator to be available.  It can be NULL at
     998             :          * this point if this is a recursive call. */
     999      170583 :         if (!m->sa)
    1000        5180 :                 m->sa = sa_create(m->pa);
    1001      170583 :         if (!m->sa) {
    1002           0 :                 c->mode = FINISHCLIENT;
    1003           0 :                 throw(SQL, "SQLparser", SQLSTATE(HY013) MAL_MALLOC_FAIL " for SQL allocator");
    1004             :         }
    1005      170583 :         if (eb_savepoint(&m->sa->eb)) {
    1006           0 :                 sa_reset(m->sa);
    1007             : 
    1008           0 :                 throw(SQL, "SQLparser", SQLSTATE(HY001) MAL_MALLOC_FAIL " for SQL allocator");
    1009             :         }
    1010             :         opt = 0;
    1011             :         preparedid = -1;
    1012             : 
    1013      170583 :         m->emode = m_normal;
    1014      170583 :         m->emod = mod_none;
    1015      170583 :         if (be->language == 'X') {
    1016             :                 int n = 0, v, off, len;
    1017             : 
    1018       20458 :                 if (strncmp(in->buf + in->pos, "export ", 7) == 0)
    1019        7497 :                         n = sscanf(in->buf + in->pos + 7, "%d %d %d", &v, &off, &len);
    1020             : 
    1021       20458 :                 if (n == 2 || n == 3) {
    1022        7497 :                         if (n == 2)
    1023           9 :                                 len = m->reply_size;
    1024        7497 :                         if ((ok = mvc_export_chunk(be, out, v, off, len < 0 ? BUN_NONE : (BUN) len)) < 0) {
    1025           0 :                                 msg = createException(SQL, "SQLparser", SQLSTATE(45000) "Result set construction failed: %s", mvc_export_error(be, out, ok));
    1026           0 :                                 goto finalize;
    1027             :                         }
    1028             : 
    1029        7497 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1030       20458 :                         return MAL_SUCCEED;
    1031             :                 }
    1032       12961 :                 if (strncmp(in->buf + in->pos, "close ", 6) == 0) {
    1033             :                         res_table *t;
    1034             : 
    1035           5 :                         v = (int) strtol(in->buf + in->pos + 6, NULL, 0);
    1036           5 :                         t = res_tables_find(be->results, v);
    1037           5 :                         if (t)
    1038           5 :                                 be->results = res_tables_remove(be->results, t);
    1039           5 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1040           5 :                         return MAL_SUCCEED;
    1041             :                 }
    1042       12956 :                 if (strncmp(in->buf + in->pos, "release ", 8) == 0) {
    1043             :                         cq *q = NULL;
    1044             : 
    1045         203 :                         v = (int) strtol(in->buf + in->pos + 8, NULL, 0);
    1046         203 :                         if ((q = qc_find(m->qc, v)) != NULL)
    1047         197 :                                  qc_delete(m->qc, q);
    1048         203 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1049         203 :                         return MAL_SUCCEED;
    1050             :                 }
    1051       12753 :                 if (strncmp(in->buf + in->pos, "auto_commit ", 12) == 0) {
    1052             :                         int commit;
    1053        3685 :                         v = (int) strtol(in->buf + in->pos + 12, NULL, 10);
    1054        3685 :                         commit = (!m->session->auto_commit && v);
    1055        3685 :                         m->session->auto_commit = (v) != 0;
    1056        3685 :                         m->session->ac_on_commit = m->session->auto_commit;
    1057        3685 :                         if (m->session->tr->active) {
    1058           0 :                                 if (commit) {
    1059           0 :                                         msg = mvc_commit(m, 0, NULL, true);
    1060             :                                 } else {
    1061           0 :                                         msg = mvc_rollback(m, 0, NULL, true);
    1062             :                                 }
    1063             :                         }
    1064        3685 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1065        3685 :                         if (msg != NULL)
    1066           0 :                                 goto finalize;
    1067             :                         return MAL_SUCCEED;
    1068             :                 }
    1069             :                 static const char* columnar_protocol = "columnar_protocol ";
    1070        9068 :                 if (strncmp(in->buf + in->pos, columnar_protocol, strlen(columnar_protocol)) == 0) {
    1071           0 :                         v = (int) strtol(in->buf + in->pos + strlen(columnar_protocol), NULL, 10);
    1072             : 
    1073           0 :                         c->protocol = v?PROTOCOL_COLUMNAR:PROTOCOL_9;
    1074             : 
    1075           0 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1076           0 :                         return MAL_SUCCEED;
    1077             :                 }
    1078        9068 :                 if (strncmp(in->buf + in->pos, "reply_size ", 11) == 0) {
    1079        5550 :                         v = (int) strtol(in->buf + in->pos + 11, NULL, 10);
    1080        5550 :                         if (v < -1) {
    1081           0 :                                 msg = createException(SQL, "SQLparser", SQLSTATE(42000) "Reply_size cannot be negative");
    1082           0 :                                 goto finalize;
    1083             :                         }
    1084        5550 :                         m->reply_size = v;
    1085        5550 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1086        5550 :                         return MAL_SUCCEED;
    1087             :                 }
    1088        3518 :                 if (strncmp(in->buf + in->pos, "sizeheader", 10) == 0) { // no underscore
    1089        3518 :                         v = (int) strtol(in->buf + in->pos + 10, NULL, 10);
    1090        3518 :                         be->sizeheader = v != 0;
    1091        3518 :                         in->pos = in->len;        /* HACK: should use parsed length */
    1092        3518 :                         return MAL_SUCCEED;
    1093             :                 }
    1094           0 :                 if (strncmp(in->buf + in->pos, "quit", 4) == 0) {
    1095           0 :                         c->mode = FINISHCLIENT;
    1096           0 :                         return MAL_SUCCEED;
    1097             :                 }
    1098           0 :                 msg = createException(SQL, "SQLparser", SQLSTATE(42000) "Unrecognized X command: %s\n", in->buf + in->pos);
    1099           0 :                 goto finalize;
    1100             :         }
    1101      150125 :         if (be->language !='S') {
    1102           0 :                 msg = createException(SQL, "SQLparser", SQLSTATE(42000) "Unrecognized language prefix: %ci\n", be->language);
    1103           0 :                 in->pos = in->len;        /* skip rest of the input */
    1104           0 :                 c->mode = FINISHCLIENT; /* and disconnect, as client doesn't respect the mapi protocol */
    1105           0 :                 goto finalize;
    1106             :         }
    1107             : 
    1108      299815 :         if ((err = sqlparse(m)) ||
    1109             :             /* Only forget old errors on transaction boundaries */
    1110      299380 :             (mvc_status(m) && m->type != Q_TRANS) || !m->sym) {
    1111       28717 :                 if (!err &&m->scanner.started)       /* repeat old errors, with a parsed query */
    1112        1381 :                         err = mvc_status(m);
    1113       28717 :                 if (err && *m->errstr) {
    1114        1204 :                         if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
    1115        1203 :                                 msg = createException(PARSE, "SQLparser", "%s", m->errstr);
    1116             :                         else
    1117           1 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
    1118        1204 :                         *m->errstr = 0;
    1119             :                 }
    1120       28717 :                 if (m->sym)
    1121         592 :                         msg = handle_error(m, pstatus, msg);
    1122       28717 :                 sqlcleanup(be, err);
    1123       28717 :                 goto finalize;
    1124             :         }
    1125             :         /*
    1126             :          * We have dealt with the first parsing step and advanced the input reader
    1127             :          * to the next statement (if any).
    1128             :          * Now is the time to also perform the semantic analysis, optimize and
    1129             :          * produce code.
    1130             :          */
    1131      121408 :         be->q = NULL;
    1132      121408 :         c->query = query_cleaned(m->sa, QUERY(m->scanner));
    1133             : 
    1134      121408 :         if (c->query == NULL) {
    1135             :                 err = 1;
    1136           0 :                 msg = createException(PARSE, "SQLparser", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1137      121408 :         } else if (m->emode == m_deallocate) {
    1138           8 :                 AtomNode *an = (AtomNode *) m->sym;
    1139           8 :                 assert(m->sym->type == type_symbol && an->a->data.vtype == TYPE_int);
    1140           8 :                 preparedid = an->a->data.val.ival;
    1141             : 
    1142           8 :                 if (preparedid > -1) /* The -1 case represents the deallocate the entire query cache */
    1143           4 :                         be->q = qc_find(m->qc, preparedid);
    1144             : 
    1145           8 :                 if (preparedid > -1) {
    1146             :                         const char *mode = "DEALLOC";
    1147           4 :                         if (!be->q) {
    1148             :                                 err = -1;
    1149           2 :                                 msg = createException(SQL, mode, SQLSTATE(07003) "No prepared statement with id: %d\n", preparedid);
    1150           2 :                                 *m->errstr = 0;
    1151           2 :                                 msg = handle_error(m, pstatus, msg);
    1152           2 :                                 sqlcleanup(be, err);
    1153           2 :                                 goto finalize;
    1154             :                         }
    1155             :                 }
    1156             : 
    1157           6 :                 m->type = Q_SCHEMA; /* TODO DEALLOCATE statements don't fit for Q_SCHEMA */
    1158           6 :                 scanner_query_processed(&(m->scanner));
    1159             :         } else {
    1160      121400 :                 sql_rel *r = sql_symbol2relation(be, m->sym);
    1161             : 
    1162      121400 :                 if (!r || (err = mvc_status(m) && m->type != Q_TRANS && *m->errstr)) {
    1163        2069 :                         if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
    1164        2069 :                                 msg = createException(PARSE, "SQLparser", "%s", m->errstr);
    1165             :                         else
    1166           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
    1167        2069 :                         *m->errstr = 0;
    1168        2069 :                         msg = handle_error(m, pstatus, msg);
    1169        2069 :                         sqlcleanup(be, err);
    1170        2069 :                         goto finalize;
    1171             :                 }
    1172             : 
    1173      119331 :                 if (m->emode != m_prepare) {
    1174      119021 :                         scanner_query_processed(&(m->scanner));
    1175             : 
    1176             :                         err = 0;
    1177      119021 :                         setVarType(c->curprg->def, 0, 0);
    1178      119021 :                         if (be->subbackend && be->subbackend->check(be->subbackend, r)) {
    1179           0 :                                 res_table *rt = NULL;
    1180           0 :                                 if (be->subbackend->exec(be->subbackend, r, be->result_id++, &rt) == NULL) { /* on error fall back */
    1181           0 :                                         if (rt) {
    1182           0 :                                                 rt->next = be->results;
    1183           0 :                                                 be->results = rt;
    1184             :                                         }
    1185           0 :                                         return NULL;
    1186             :                                 }
    1187             :                         }
    1188             : 
    1189      119021 :                         if (backend_dumpstmt(be, c->curprg->def, r, !(m->emod & mod_exec), 0, c->query) < 0)
    1190             :                                 err = 1;
    1191             :                         else
    1192      119015 :                                 opt = (m->emod & mod_exec) == 0;//1;
    1193             :                 } else {
    1194         310 :                         char *q_copy = sa_strdup(m->sa, c->query);
    1195             : 
    1196         310 :                         be->q = NULL;
    1197         310 :                         if (!q_copy) {
    1198             :                                 err = 1;
    1199           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1200             :                         } else {
    1201         310 :                                 be->q = qc_insert(m->qc, m->sa,        /* the allocator */
    1202             :                                                   r,    /* keep relational query */
    1203         310 :                                                   m->sym,    /* the sql symbol tree */
    1204             :                                                   m->params, /* the argument list */
    1205             :                                                   m->type,   /* the type of the statement */
    1206             :                                                   q_copy,
    1207         310 :                                                   be->no_mitosis);
    1208             :                         }
    1209         310 :                         if (!be->q) {
    1210             :                                 err = 1;
    1211           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1212             :                         }
    1213         310 :                         scanner_query_processed(&(m->scanner));
    1214         310 :                         if (be->q && backend_dumpproc(be, c, be->q, r) < 0)
    1215             :                                 err = 1;
    1216             : 
    1217             :                         /* passed over to query cache, used during dumpproc */
    1218         310 :                         m->sa = NULL;
    1219         310 :                         m->sym = NULL;
    1220         310 :                         m->params = NULL;
    1221             :                         /* register name in the namespace */
    1222         310 :                         if (be->q) {
    1223         310 :                                 assert(strlen(be->q->name) < IDLENGTH);
    1224         310 :                                 be->q->name = putName(be->q->name);
    1225         310 :                                 if (!be->q->name) {
    1226             :                                         err = 1;
    1227           0 :                                         msg = createException(PARSE, "SQLparser", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1228             :                                 }
    1229             :                         }
    1230             :                 }
    1231             :         }
    1232      119337 :         if (err)
    1233          13 :                 m->session->status = -10;
    1234      119337 :         if (err == 0) {
    1235             :                 /* no parsing error encountered, finalize the code of the query wrapper */
    1236      119324 :                 if (m->emode == m_deallocate) {
    1237           6 :                         assert(be->q || preparedid == -1);
    1238           6 :                         if (be->q) {
    1239           2 :                                 qc_delete(m->qc, be->q);
    1240             :                         } else {
    1241           4 :                                 qc_clean(m->qc);
    1242             :                         }
    1243             :                         /* For deallocate statements just export a simple output */
    1244           6 :                         if (!GDKembedded() && (err = mvc_export_operation(be, c->fdout, "", c->curprg->def->starttime, c->curprg->def->optimize)) < 0) {
    1245           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(45000) "Export operation failed: %s", mvc_export_error(be, c->fdout, err));
    1246           0 :                                 MSresetInstructions(c->curprg->def, oldstop);
    1247           0 :                                 freeVariables(c, c->curprg->def, NULL, oldvtop, oldvid);
    1248           0 :                                 goto finalize;
    1249             :                         }
    1250      119318 :                 } else if (be->q) {
    1251         302 :                         assert(m->emode == m_prepare);
    1252             :                         /* For prepared queries, return a table with result set structure*/
    1253             :                         /* optimize the code block and rename it */
    1254         302 :                         if ((err = mvc_export_prepare(be, c->fdout)) < 0) {
    1255           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(45000) "Export operation failed: %s", mvc_export_error(be, c->fdout, err));
    1256           0 :                                 MSresetInstructions(c->curprg->def, oldstop);
    1257           0 :                                 freeVariables(c, c->curprg->def, NULL, oldvtop, oldvid);
    1258           0 :                                 goto finalize;
    1259             :                         }
    1260             :                 }
    1261             : 
    1262      119324 :                 pushEndInstruction(c->curprg->def);
    1263             :                 /* check the query wrapper for errors */
    1264      119324 :                 if( msg == MAL_SUCCEED)
    1265      119324 :                         msg = chkTypes(c->usermodule, c->curprg->def, TRUE);
    1266             : 
    1267             :                 /* in case we had produced a non-cachable plan, the optimizer should be called */
    1268      119324 :                 if (msg == MAL_SUCCEED && opt ) {
    1269      113169 :                         msg = SQLoptimizeQuery(c, c->curprg->def);
    1270             : 
    1271      113169 :                         if (msg != MAL_SUCCEED) {
    1272           0 :                                 str other = c->curprg->def->errors;
    1273             :                                 /* In debugging mode you may want to assess what went wrong in the optimizers*/
    1274             : #ifndef NDEBUG
    1275           0 :                                 if( m->emod & mod_debug)
    1276           0 :                                         runMALDebugger(c, c->curprg->def);
    1277             : #endif
    1278           0 :                                 c->curprg->def->errors = 0;
    1279           0 :                                 MSresetInstructions(c->curprg->def, oldstop);
    1280           0 :                                 freeVariables(c, c->curprg->def, NULL, oldvtop, oldvid);
    1281           0 :                                 if (other != msg)
    1282           0 :                                         freeException(other);
    1283           0 :                                 goto finalize;
    1284             :                         }
    1285             :                 }
    1286             :                 //printFunction(c->fdout, c->curprg->def, 0, LIST_MAL_ALL);
    1287             :                 /* we know more in this case than chkProgram(c->fdout, c->usermodule, c->curprg->def); */
    1288      119324 :                 if (msg == MAL_SUCCEED && c->curprg->def->errors) {
    1289           0 :                         msg = c->curprg->def->errors;
    1290           0 :                         c->curprg->def->errors = 0;
    1291             :                         /* restore the state */
    1292           0 :                         MSresetInstructions(c->curprg->def, oldstop);
    1293           0 :                         freeVariables(c, c->curprg->def, NULL, oldvtop, oldvid);
    1294           0 :                         if (msg == NULL && *m->errstr){
    1295           0 :                                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
    1296           0 :                                         msg = createException(PARSE, "SQLparser", "%s", m->errstr);
    1297             :                                 else
    1298           0 :                                         msg = createException(PARSE, "SQLparser", SQLSTATE(M0M27) "Semantic errors %s", m->errstr);
    1299           0 :                                 *m->errstr = 0;
    1300           0 :                         } else if (msg) {
    1301           0 :                                 str newmsg = createException(PARSE, "SQLparser", SQLSTATE(M0M27) "Semantic errors %s", msg);
    1302           0 :                                 freeException(msg);
    1303             :                                 msg = newmsg;
    1304             :                         }
    1305             :                 }
    1306             :         }
    1307      119337 : finalize:
    1308      150125 :         if (msg) {
    1309        3867 :                 sqlcleanup(be, 0);
    1310        3867 :                 c->query = NULL;
    1311             :         }
    1312      150125 :         return msg;
    1313             : }
    1314             : 
    1315             : str
    1316      166716 : SQLengine(Client c)
    1317             : {
    1318      166716 :         backend *be = (backend *) c->sqlcontext;
    1319      166716 :         if (be && be->subbackend)
    1320           0 :                 be->subbackend->reset(be->subbackend);
    1321      166716 :         return SQLengineIntern(c, be);
    1322             : }
    1323             : 
    1324             : str
    1325         310 : SQLCacheRemove(Client c, const char *nme)
    1326             : {
    1327             :         Symbol s;
    1328             : 
    1329         310 :         s = findSymbolInModule(c->usermodule, nme);
    1330         310 :         if (s == NULL)
    1331           8 :                 throw(MAL, "cache.remove", SQLSTATE(42000) "internal error, symbol missing\n");
    1332         302 :         deleteSymbol(c->usermodule, s);
    1333         302 :         return MAL_SUCCEED;
    1334             : }
    1335             : 
    1336             : str
    1337        5517 : SQLcallback(Client c, str msg)
    1338             : {
    1339        5517 :         if (msg) {
    1340             :                 /* remove exception decoration */
    1341       11352 :                 for (char *m = msg; m && *m; ) {
    1342        5835 :                         char *n = strchr(m, '\n');
    1343        5835 :                         char *s = getExceptionMessageAndState(m);
    1344        5835 :                         mnstr_printf(c->fdout, "!%.*s\n", (int) (n - s), s);
    1345             :                         m = n;
    1346        5835 :                         if (n) {
    1347        2675 :                                 m++; /* include newline */
    1348             :                         }
    1349             :                 }
    1350        5517 :                 freeException(msg);
    1351        5517 :                 return MAL_SUCCEED;
    1352             :         }
    1353           0 :         return MALcallback(c, msg);
    1354             : }
    1355             : 
    1356             : str
    1357         186 : SYSupdate_tables(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1358             : {
    1359         186 :         mvc *m = ((backend *) cntxt->sqlcontext)->mvc;
    1360             : 
    1361             :         (void) mb;
    1362             :         (void) stk;
    1363             :         (void) pci;
    1364             : 
    1365         186 :         sql_trans_update_tables(m->session->tr, mvc_bind_schema(m, "sys"));
    1366         186 :         return MAL_SUCCEED;
    1367             : }
    1368             : 
    1369             : str
    1370         186 : SYSupdate_schemas(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1371             : {
    1372         186 :         mvc *m = ((backend *) cntxt->sqlcontext)->mvc;
    1373             : 
    1374             :         (void) mb;
    1375             :         (void) stk;
    1376             :         (void) pci;
    1377             : 
    1378         186 :         sql_trans_update_schemas(m->session->tr);
    1379         186 :         return MAL_SUCCEED;
    1380             : }

Generated by: LCOV version 1.14