LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_execute.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 452 596 75.8 %
Date: 2024-10-03 20:03:20 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * SQL execution
      15             :  * N. Nes, M.L. Kersten
      16             :  */
      17             : /*
      18             :  * Execution of SQL instructions.
      19             :  * Before we are can process SQL statements the global catalog should be initialized.
      20             :  */
      21             : #include "monetdb_config.h"
      22             : #include "mal_backend.h"
      23             : #include "sql_scenario.h"
      24             : #include "sql_result.h"
      25             : #include "sql_gencode.h"
      26             : #include "sql_assert.h"
      27             : #include "sql_execute.h"
      28             : #include "sql_env.h"
      29             : #include "sql_mvc.h"
      30             : #include "sql_user.h"
      31             : #include "sql_optimizer.h"
      32             : #include "sql_datetime.h"
      33             : #include "rel_select.h"
      34             : #include "rel_rel.h"
      35             : #include "rel_exp.h"
      36             : #include "rel_dump.h"
      37             : #include "gdk_time.h"
      38             : #include "optimizer.h"
      39             : #include "opt_inline.h"
      40             : #include <unistd.h>
      41             : 
      42             : /* #define _SQL_COMPILE */
      43             : 
      44             : /*
      45             : * BEWARE: SQLstatementIntern only commits after all statements found
      46             : * in expr are executed, when autocommit mode is enabled.
      47             : *
      48             : * The tricky part for this statement is to ensure that the SQL statement
      49             : * is executed within the client context specified. This leads to context juggling.
      50             : */
      51             : 
      52             : /*
      53             :  * The trace operation collects the events in the BATs
      54             :  * and creates a secondary result set upon termination
      55             :  * of the query.
      56             :  *
      57             :  * SQLsetTrace extends the MAL plan with code to collect the events.
      58             :  * from the profile cache and returns it as a secondary resultset.
      59             :  */
      60             : static str
      61           4 : SQLsetTrace(Client cntxt, MalBlkPtr mb)
      62             : {
      63           4 :         InstrPtr q, resultset;
      64           4 :         InstrPtr tbls, cols, types, clen, scale;
      65           4 :         str msg = MAL_SUCCEED;
      66           4 :         int k;
      67             : 
      68           4 :         if((msg = startTrace(cntxt)) != MAL_SUCCEED)
      69             :                 return msg;
      70           4 :         clearTrace(cntxt);
      71             : 
      72         126 :         for(k = mb->stop-1; k>0; k--)
      73         126 :                 if( getInstrPtr(mb,k)->token ==ENDsymbol)
      74             :                         break;
      75           4 :         mb->stop = k;
      76             : 
      77           4 :         q = newStmt(mb, profilerRef, stoptraceRef);
      78           4 :         if (q == NULL) {
      79           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      80             :         }
      81           4 :         pushInstruction(mb, q);
      82             : 
      83             :         /* cook a new resultSet instruction */
      84           4 :         resultset = newInstruction(mb,sqlRef, resultSetRef);
      85           4 :         if (resultset == NULL) {
      86           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      87             :         }
      88           4 :         getArg(resultset,0) = newTmpVariable(mb, TYPE_int);
      89             : 
      90             :         /* build table defs */
      91           4 :         tbls = newStmt(mb,batRef, newRef);
      92           4 :         if (tbls == NULL) {
      93           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      94             :         }
      95           4 :         setVarType(mb, getArg(tbls,0), newBatType(TYPE_str));
      96           4 :         tbls = pushType(mb, tbls, TYPE_str);
      97           4 :         pushInstruction(mb, tbls);
      98             : 
      99           4 :         q = newStmt(mb,batRef,appendRef);
     100           4 :         if (q == NULL) {
     101           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     102             :         }
     103           4 :         q = pushArgument(mb,q,getArg(tbls,0));
     104           4 :         q = pushStr(mb,q,".trace");
     105           4 :         k = getArg(q,0);
     106           4 :         pushInstruction(mb, q);
     107             : 
     108           4 :         q = newStmt(mb,batRef,appendRef);
     109           4 :         if (q == NULL) {
     110           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     111             :         }
     112           4 :         q = pushArgument(mb,q,k);
     113           4 :         q = pushStr(mb,q,".trace");
     114           4 :         pushInstruction(mb, q);
     115             : 
     116           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     117             : 
     118             :         /* build column defs */
     119           4 :         cols = newStmt(mb,batRef, newRef);
     120           4 :         if (cols == NULL) {
     121           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     122             :         }
     123           4 :         setVarType(mb, getArg(cols,0), newBatType(TYPE_str));
     124           4 :         cols = pushType(mb, cols, TYPE_str);
     125           4 :         pushInstruction(mb, cols);
     126             : 
     127           4 :         q = newStmt(mb,batRef,appendRef);
     128           4 :         if (q == NULL) {
     129           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     130             :         }
     131           4 :         q = pushArgument(mb,q,getArg(cols,0));
     132           4 :         q = pushStr(mb,q,"usec");
     133           4 :         k = getArg(q,0);
     134           4 :         pushInstruction(mb, q);
     135             : 
     136           4 :         q = newStmt(mb,batRef,appendRef);
     137           4 :         if (q == NULL) {
     138           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     139             :         }
     140           4 :         q = pushArgument(mb,q, k);
     141           4 :         q = pushStr(mb,q,"statement");
     142           4 :         pushInstruction(mb, q);
     143             : 
     144           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     145             : 
     146             :         /* build type defs */
     147           4 :         types = newStmt(mb,batRef, newRef);
     148           4 :         if (types == NULL) {
     149           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     150             :         }
     151           4 :         setVarType(mb, getArg(types,0), newBatType(TYPE_str));
     152           4 :         types = pushType(mb, types, TYPE_str);
     153           4 :         pushInstruction(mb, types);
     154             : 
     155           4 :         q = newStmt(mb,batRef,appendRef);
     156           4 :         if (q == NULL) {
     157           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     158             :         }
     159           4 :         q = pushArgument(mb,q, getArg(types,0));
     160           4 :         q = pushStr(mb,q,"bigint");
     161           4 :         k = getArg(q,0);
     162           4 :         pushInstruction(mb, q);
     163             : 
     164           4 :         q = newStmt(mb,batRef,appendRef);
     165           4 :         if (q == NULL) {
     166           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     167             :         }
     168           4 :         q = pushArgument(mb,q, k);
     169           4 :         q = pushStr(mb,q,"varchar");
     170           4 :         pushInstruction(mb, q);
     171             : 
     172           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     173             : 
     174             :         /* build scale defs */
     175           4 :         clen = newStmt(mb,batRef, newRef);
     176           4 :         if (clen == NULL) {
     177           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     178             :         }
     179           4 :         setVarType(mb, getArg(clen,0), newBatType(TYPE_int));
     180           4 :         clen = pushType(mb, clen, TYPE_int);
     181           4 :         pushInstruction(mb, clen);
     182             : 
     183           4 :         q = newStmt(mb,batRef,appendRef);
     184           4 :         if (q == NULL) {
     185           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     186             :         }
     187           4 :         q = pushArgument(mb,q, getArg(clen,0));
     188           4 :         q = pushInt(mb,q,64);
     189           4 :         k = getArg(q,0);
     190           4 :         pushInstruction(mb, q);
     191             : 
     192           4 :         q = newStmt(mb,batRef,appendRef);
     193           4 :         if (q == NULL) {
     194           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     195             :         }
     196           4 :         q = pushArgument(mb,q, k);
     197           4 :         q = pushInt(mb,q,0);
     198           4 :         pushInstruction(mb, q);
     199             : 
     200           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     201             : 
     202             :         /* build scale defs */
     203           4 :         scale = newStmt(mb,batRef, newRef);
     204           4 :         if (scale == NULL) {
     205           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     206             :         }
     207           4 :         setVarType(mb, getArg(scale,0), newBatType(TYPE_int));
     208           4 :         scale = pushType(mb, scale, TYPE_int);
     209           4 :         pushInstruction(mb, scale);
     210             : 
     211           4 :         q = newStmt(mb,batRef,appendRef);
     212           4 :         if (q == NULL) {
     213           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     214             :         }
     215           4 :         q = pushArgument(mb,q, getArg(scale,0));
     216           4 :         q = pushInt(mb,q,0);
     217           4 :         k = getArg(q,0);
     218           4 :         pushInstruction(mb, q);
     219             : 
     220           4 :         q = newStmt(mb,batRef,appendRef);
     221           4 :         if (q == NULL) {
     222           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     223             :         }
     224           4 :         q = pushArgument(mb, q, k);
     225           4 :         q = pushInt(mb,q,0);
     226           4 :         pushInstruction(mb, q);
     227             : 
     228           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     229             : 
     230             :         /* add the ticks column */
     231             : 
     232           4 :         q = newStmt(mb, profilerRef, getTraceRef);
     233           4 :         if (q == NULL) {
     234           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     235             :         }
     236           4 :         q = pushStr(mb, q, putName("usec"));
     237           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     238           4 :         pushInstruction(mb, q);
     239             : 
     240             :         /* add the stmt column */
     241           4 :         q = newStmt(mb, profilerRef, getTraceRef);
     242           4 :         if (q == NULL) {
     243           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     244             :         }
     245           4 :         q = pushStr(mb, q, putName("stmt"));
     246           4 :         resultset = pushArgument(mb,resultset, getArg(q,0));
     247           4 :         pushInstruction(mb, q);
     248             : 
     249           4 :         pushInstruction(mb,resultset);
     250           4 :         pushEndInstruction(mb);
     251           4 :         msg = chkTypes(cntxt->usermodule, mb, TRUE);
     252           4 :         return msg;
     253             : }
     254             : 
     255             : str
     256      559218 : SQLrun(Client c, mvc *m)
     257             : {
     258      559218 :         str msg = MAL_SUCCEED;
     259      559218 :         MalBlkPtr mb = c->curprg->def;
     260             : 
     261      559218 :         assert(!*m->errstr);
     262             : 
     263      559218 :         TRC_INFO(SQL_EXECUTION, "Executing: %s", c->query);
     264      559219 :         MT_thread_setworking(c->query);
     265             : 
     266      559218 :         if (m->emod & mod_explain) {
     267          65 :                 if (c->curprg->def)
     268          65 :                         printFunction(c->fdout, mb, 0, LIST_MAL_NAME | LIST_MAL_VALUE  | LIST_MAL_TYPE |  LIST_MAL_MAPI);
     269             :         } else {
     270      559153 :                 if (m->emod & mod_trace){
     271           4 :                         if((msg = SQLsetTrace(c,mb)) == MAL_SUCCEED) {
     272           4 :                                 setVariableScope(mb);
     273           4 :                                 MT_lock_set(&mal_contextLock);
     274           4 :                                 c->idle = 0;
     275           4 :                                 c->lastcmd = time(0);
     276           4 :                                 MT_lock_unset(&mal_contextLock);
     277           4 :                                 msg = runMAL(c, mb, 0, 0);
     278           4 :                                 stopTrace(c);
     279             :                         }
     280             :                 } else {
     281      559149 :                         setVariableScope(mb);
     282      559149 :                         MT_lock_set(&mal_contextLock);
     283      559149 :                         c->idle = 0;
     284      559149 :                         c->lastcmd = time(0);
     285      559149 :                         MT_lock_unset(&mal_contextLock);
     286      559149 :                         msg = runMAL(c, mb, 0, 0);
     287             :                 }
     288      559153 :                 resetMalBlk(mb);
     289             :         }
     290             :         /* after the query has been finished we enter the idle state */
     291      559209 :         MT_lock_set(&mal_contextLock);
     292      559218 :         c->idle = time(0);
     293      559218 :         c->lastcmd = 0;
     294      559218 :         MT_lock_unset(&mal_contextLock);
     295      559218 :         MT_thread_setworking(NULL);
     296      559218 :         return msg;
     297             : }
     298             : 
     299             : /*
     300             :  * Escape single quotes and backslashes. This is important to do before calling
     301             :  * SQLstatementIntern, if we are pasting user provided strings into queries
     302             :  * passed to the SQLstatementIntern. Otherwise we open ourselves to SQL
     303             :  * injection attacks.
     304             :  *
     305             :  * It returns the input string with all the single quotes(') and the backslashes
     306             :  * (\) doubled, or NULL, if it could not allocate enough space.
     307             :  *
     308             :  * The caller is responsible to free the returned value.
     309             :  */
     310             : str
     311           0 : SQLescapeString(str s)
     312             : {
     313           0 :         str ret = NULL;
     314           0 :         char *p, *q;
     315           0 :         size_t len = 0;
     316             : 
     317           0 :         if(!s) {
     318             :                 return NULL;
     319             :         }
     320             : 
     321             :         /* At most we will need 2*strlen(s) + 1 characters */
     322           0 :         len = strlen(s);
     323           0 :         ret = (str)GDKmalloc(2*len + 1);
     324           0 :         if (!ret) {
     325             :                 return NULL;
     326             :         }
     327             : 
     328           0 :         for (p = s, q = ret; *p != '\0'; p++, q++) {
     329           0 :                 *q = *p;
     330           0 :                 if (*p == '\'') {
     331           0 :                         *(++q) = '\'';
     332             :                 }
     333           0 :                 else if (*p == '\\') {
     334           0 :                         *(++q) = '\\';
     335             :                 }
     336             :         }
     337             : 
     338           0 :         *q = '\0';
     339           0 :         return ret;
     340             : }
     341             : 
     342             : str
     343       10395 : SQLstatementIntern(Client c, const char *expr, const char *nme, bit execute, bit output, res_table **result)
     344             : {
     345       10395 :         int status = 0, err = 0, oldvtop, oldstop = 1, inited = 0, ac, sizeframes, topframes;
     346       10395 :         unsigned int label;
     347       10395 :         mvc *o = NULL, *m = NULL;
     348       10395 :         sql_frame **frames;
     349       10395 :         list *global_vars;
     350       10395 :         buffer *b = NULL;
     351       10395 :         char *n = NULL;
     352       10395 :         bstream *bs = NULL;
     353       10395 :         stream *buf = NULL;
     354       10395 :         str msg = MAL_SUCCEED;
     355       10395 :         backend *be = NULL, *sql = (backend *) c->sqlcontext;
     356       10395 :         Symbol backup = NULL;
     357       10395 :         size_t len = strlen(expr);
     358             : 
     359       10395 :         if (!sql) {
     360           9 :                 inited = 1;
     361           9 :                 msg = SQLinitClient(c, NULL, NULL, NULL);
     362           9 :                 sql = (backend *) c->sqlcontext;
     363             :         }
     364       10395 :         if (msg){
     365           0 :                 freeException(msg);
     366           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY002) "Catalogue not available");
     367             :         }
     368             : 
     369       10395 :         m = sql->mvc;
     370       10395 :         ac = m->session->auto_commit;
     371       10395 :         o = MNEW(mvc);
     372       10395 :         if (!o) {
     373           0 :                 if (inited) {
     374           0 :                         msg = SQLresetClient(c);
     375           0 :                         freeException(msg);
     376             :                 }
     377           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     378             :         }
     379       10395 :         *o = *m;
     380             : 
     381             :         /* create private allocator */
     382       10395 :         m->sa = NULL;
     383       10395 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED) {
     384           0 :                 be = sql;
     385           0 :                 sql = NULL;
     386           0 :                 goto endofcompile;
     387             :         }
     388       10395 :         status = m->session->status;
     389             : 
     390       10395 :         m->type = Q_PARSE;
     391       10395 :         be = sql;
     392       10395 :         sql = backend_create(m, c);
     393       10395 :         if (sql == NULL) {
     394           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     395           0 :                 goto endofcompile;
     396             :         }
     397       10395 :         sql->output_format = be->output_format;
     398       10395 :         if (!output) {
     399       10383 :                 sql->output_format = OFMT_NONE;
     400             :         }
     401       10395 :         sql->depth++;
     402             : 
     403       10395 :         m->user_id = m->role_id = USER_MONETDB;
     404       10395 :         if (result)
     405        1303 :                 m->reply_size = -2; /* do not clean up result tables */
     406             : 
     407             :         /* mimic a client channel on which the query text is received */
     408       10395 :         b = malloc(sizeof(buffer));
     409       10395 :         if (b == NULL) {
     410           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     411           0 :                 goto endofcompile;
     412             :         }
     413       10395 :         n = malloc(len + 1 + 1);
     414       10395 :         if (n == NULL) {
     415           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     416           0 :                 goto endofcompile;
     417             :         }
     418       10395 :         strcpy_len(n, expr, len + 1);
     419       10395 :         n[len] = '\n';
     420       10395 :         n[len + 1] = 0;
     421       10395 :         len++;
     422       10395 :         buffer_init(b, n, len);
     423       10395 :         buf = buffer_rastream(b, "sqlstatement");
     424       10395 :         if (buf == NULL) {
     425           0 :                 buffer_destroy(b); /* n and b will be freed by the buffer */
     426           0 :                 b = NULL;
     427           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     428           0 :                 goto endofcompile;
     429             :         }
     430       10395 :         bs = bstream_create(buf, b->len);
     431       10395 :         if (bs == NULL) {
     432           0 :                 mnstr_destroy(buf);
     433           0 :                 buffer_destroy(b);
     434           0 :                 b = NULL;
     435           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     436           0 :                 goto endofcompile;
     437             :         }
     438       10395 :         scanner_init(&m->scanner, bs, NULL);
     439       10395 :         m->scanner.mode = LINE_N;
     440       10395 :         bstream_next(m->scanner.rs);
     441             : 
     442       10395 :         m->params = NULL;
     443       10395 :         m->session->auto_commit = 0;
     444       10395 :         if (!m->sa && !(m->sa = sa_create(m->pa)) ) {
     445           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     446           0 :                 goto endofcompile;
     447             :         }
     448             : 
     449             :         /*
     450             :          * System has been prepared to parse it and generate code.
     451             :          * Scan the complete string for SQL statements, stop at the first error.
     452             :          */
     453       10395 :         c->sqlcontext = sql;
     454       10395 :         if (c->curprg) {
     455       10373 :                 backup = c->curprg;
     456       10373 :                 c->curprg = NULL;
     457             :         }
     458             : 
     459      314634 :         while (msg == MAL_SUCCEED && m->scanner.rs->pos < m->scanner.rs->len) {
     460      304242 :                 sql_rel *r;
     461             : 
     462      304242 :                 m->sym = NULL;
     463      608484 :                 if ((err = sqlparse(m)) ||
     464             :                     /* Only forget old errors on transaction boundaries */
     465      608484 :                     (mvc_status(m) && m->type != Q_TRANS) || !m->sym) {
     466           2 :                         if (!err)
     467           2 :                                 err = mvc_status(m);
     468           2 :                         if (*m->errstr){
     469           0 :                                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     470           0 :                                         msg = createException(PARSE, "SQLparser", "%s", m->errstr);
     471             :                                 else
     472           0 :                                         msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
     473           0 :                                 *m->errstr = 0;
     474             :                         }
     475           2 :                         sqlcleanup(sql, err);
     476           2 :                         execute = 0;
     477           2 :                         if (!err)
     478           2 :                                 continue;
     479           0 :                         goto endofcompile;
     480             :                 }
     481             : 
     482             :                 /*
     483             :                  * We have dealt with the first parsing step and advanced the input reader
     484             :                  * to the next statement (if any).
     485             :                  * Now is the time to also perform the semantic analysis,
     486             :                  * optimize and produce code.
     487             :                  * We don't search the cache for a previous incarnation yet.
     488             :                  */
     489      304240 :                 if((msg = MSinitClientPrg(c, sql_private_module_name, nme)) != MAL_SUCCEED) {
     490           0 :                         goto endofcompile;
     491             :                 }
     492      304240 :                 oldvtop = c->curprg->def->vtop;
     493      304240 :                 oldstop = c->curprg->def->stop;
     494      304240 :                 r = sql_symbol2relation(sql, m->sym);
     495             : 
     496      304240 :                 assert(m->emode != m_prepare);
     497      304240 :                 scanner_query_processed(&(m->scanner));
     498      304240 :                 if ((err = mvc_status(m)) ) {
     499           3 :                         if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     500           3 :                                 msg = createException(PARSE, "SQLparser", "%s", m->errstr);
     501             :                         else
     502           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
     503           3 :                         *m->errstr = 0;
     504           3 :                         msg = handle_error(m, status, msg);
     505           3 :                         sqlcleanup(sql, err);
     506             :                         /* restore the state */
     507           3 :                         MSresetInstructions(c->curprg->def, oldstop);
     508           3 :                         freeVariables(c, c->curprg->def, c->glb, oldvtop);
     509           3 :                         c->curprg->def->errors = 0;
     510           3 :                         goto endofcompile;
     511             :                 }
     512             :                 /* generate MAL code */
     513      304237 :                 be->depth++;
     514      304237 :                 setVarType(c->curprg->def, 0, 0);
     515      304237 :                 if (backend_dumpstmt(be, c->curprg->def, r, 1, 1, NULL) < 0)
     516           0 :                         err = 1;
     517      304237 :                 be->depth--;
     518             : 
     519      304237 :                 if (err == 0) {
     520      304237 :                         if (msg == MAL_SUCCEED)
     521      304237 :                                 msg = SQLoptimizeQuery(c, c->curprg->def);
     522      304237 :                         if (msg)
     523             :                                 err = 1;
     524             :                 }
     525             : 
     526      304237 :                 if (err) {
     527           0 :                         status = -10;
     528           0 :                         if (msg)
     529           0 :                                 msg = handle_error(m, status, msg);
     530           0 :                         sqlcleanup(sql, err);
     531             :                         /* restore the state */
     532           0 :                         MSresetInstructions(c->curprg->def, oldstop);
     533           0 :                         freeVariables(c, c->curprg->def, c->glb, oldvtop);
     534           0 :                         c->curprg->def->errors = 0;
     535           0 :                         goto endofcompile;
     536             :                 }
     537             : 
     538      304237 :                 if (execute) {
     539      304237 :                         if (!output)
     540      304225 :                                 sql->out = NULL;     /* no output stream */
     541      304237 :                         be->depth++;
     542      304237 :                         msg = SQLrun(c,m);
     543      304237 :                         be->depth--;
     544      304237 :                         if (c->curprg->def->stop > 1) {
     545           0 :                                 assert(0);
     546             :                                 MSresetInstructions(c->curprg->def, oldstop);
     547             :                                 freeVariables(c, c->curprg->def, NULL, oldvtop);
     548             :                         }
     549      304237 :                         sqlcleanup(sql, 0);
     550      304237 :                         if (!execute)
     551             :                                 goto endofcompile;
     552             :                 }
     553      304237 :                 if (sql->results) {
     554        1263 :                         if (result) { /* return all results sets */
     555        1262 :                                 *result = sql->results;
     556             :                         } else {
     557           1 :                                 if (sql->results == be->results)
     558           0 :                                         be->results = NULL;
     559           1 :                                 res_tables_destroy(sql->results);
     560             :                         }
     561        1263 :                         sql->results = NULL;
     562             :                 }
     563             :         }
     564             : /*
     565             :  * We are done; a MAL procedure resides in the cache.
     566             :  */
     567       10392 : endofcompile:
     568       10395 :         if (execute)
     569       10393 :                 MSresetInstructions(c->curprg->def, 1);
     570             : 
     571       10395 :         if (backup)
     572       10373 :                 c->curprg = backup;
     573             : 
     574       10395 :         c->sqlcontext = be;
     575       10395 :         backend_destroy(sql);
     576       10395 :         buffer_destroy(b);
     577       10395 :         bstream_destroy(m->scanner.rs);
     578       10395 :         if (m->sa)
     579       10395 :                 sa_destroy(m->sa);
     580       10395 :         m->sa = NULL;
     581       10395 :         m->sym = NULL;
     582       10395 :         m->runs = NULL;
     583             :         /* variable stack maybe resized, ie we need to keep the new stack */
     584       10395 :         label = m->label;
     585       10395 :         status = m->session->status;
     586       10395 :         global_vars = m->global_vars;
     587       10395 :         sizeframes = m->sizeframes;
     588       10395 :         topframes = m->topframes;
     589       10395 :         frames = m->frames;
     590       10395 :         *m = *o;
     591       10395 :         _DELETE(o);
     592       10395 :         m->label = label;
     593       10395 :         m->global_vars = global_vars;
     594       10395 :         m->sizeframes = sizeframes;
     595       10395 :         m->topframes = topframes;
     596       10395 :         m->frames = frames;
     597       10395 :         m->session->status = status;
     598       10395 :         m->session->auto_commit = ac;
     599       10395 :         if (inited) {
     600           9 :                 str other = SQLresetClient(c);
     601           9 :                 freeException(other);
     602             :         }
     603             :         return msg;
     604             : }
     605             : 
     606             : str
     607      254980 : SQLengineIntern(Client c, backend *be)
     608             : {
     609      254980 :         str msg = MAL_SUCCEED;
     610             :         //char oldlang = be->language;
     611      254980 :         mvc *m = be->mvc;
     612             : 
     613      254980 :         assert (m->emode != m_deallocate && m->emode != m_prepare);
     614      254980 :         assert (c->curprg->def->stop > 2);
     615             : 
     616             :         //be->language = 'D';
     617      254980 :         if (MALcommentsOnly(c->curprg->def))
     618             :                 msg = MAL_SUCCEED;
     619             :         else
     620      254980 :                 msg = SQLrun(c,m);
     621             : 
     622      254980 :         if (m->type == Q_SCHEMA && m->qc != NULL)
     623       16562 :                 qc_clean(m->qc);
     624      254980 :         be->q = NULL;
     625      254980 :         if (msg)
     626       17788 :                 m->session->status = -10;
     627      254980 :         sqlcleanup(be, (!msg) ? 0 : -1);
     628      254980 :         MSresetInstructions(c->curprg->def, 1);
     629      254979 :         freeVariables(c, c->curprg->def, NULL, be->vtop);
     630             :         //be->language = oldlang;
     631             :         /*
     632             :          * Any error encountered during execution should block further processing
     633             :          * unless auto_commit has been set.
     634             :          */
     635      254980 :         return msg;
     636             : }
     637             : 
     638             : void
     639          33 : SQLdestroyResult(res_table *destroy)
     640             : {
     641          33 :         res_table_destroy(destroy);
     642          33 : }
     643             : 
     644             : static str
     645         185 : RAcommit_statement(backend *be, str msg)
     646             : {
     647         185 :         mvc *m = be->mvc;
     648             :         /* if an error already exists set the session status to dirty */
     649         185 :         if (msg != MAL_SUCCEED && m->session->tr->active && !m->session->status)
     650           0 :                 m->session->status = -1;
     651         185 :         return msg;
     652             : }
     653             : 
     654             : /* a hook is provided to execute relational algebra expressions */
     655             : str
     656           0 : RAstatement(Client c, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     657             : {
     658           0 :         int pos = 0;
     659           0 :         str *expr = getArgReference_str(stk, pci, 1);
     660           0 :         bit *opt = getArgReference_bit(stk, pci, 2);
     661           0 :         backend *be = NULL;
     662           0 :         mvc *m = NULL;
     663           0 :         str msg = MAL_SUCCEED;
     664           0 :         sql_rel *rel;
     665           0 :         list *refs;
     666             : 
     667           0 :         if ((msg = getSQLContext(c, mb, &m, &be)) != NULL)
     668             :                 return msg;
     669           0 :         if ((msg = checkSQLContext(c)) != NULL)
     670             :                 return msg;
     671           0 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED)
     672             :                 return msg;
     673           0 :         if (!m->sa)
     674           0 :                 m->sa = sa_create(m->pa);
     675           0 :         if (!m->sa)
     676           0 :                 return RAcommit_statement(be, createException(SQL,"RAstatement",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     677           0 :         refs = sa_list(m->sa);
     678           0 :         rel = rel_read(m, *expr, &pos, refs);
     679           0 :         if (*opt && rel)
     680           0 :                 rel = sql_processrelation(m, rel, 0, 1, 0, 0);
     681           0 :         if (!rel) {
     682           0 :                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     683           0 :                         msg = createException(SQL, "RAstatement", "%s", m->errstr);
     684             :                 else
     685           0 :                         msg = createException(SQL, "RAstatement", SQLSTATE(42000) "%s", m->errstr);
     686             :         } else {
     687           0 :                 if ((msg = MSinitClientPrg(c, sql_private_module_name, "test")) != MAL_SUCCEED)
     688           0 :                         return RAcommit_statement(be, msg);
     689             : 
     690             :                 /* generate MAL code, ignoring any code generation error */
     691           0 :                 setVarType(c->curprg->def, 0, 0);
     692           0 :                 if (backend_dumpstmt(be, c->curprg->def, rel, 0, 1, NULL) < 0) {
     693           0 :                         msg = createException(SQL,"RAstatement","Program contains errors"); // TODO: use macro definition.
     694             :                 } else {
     695           0 :                         SQLaddQueryToCache(c);
     696           0 :                         msg = SQLoptimizeFunction(c,c->curprg->def);
     697           0 :                         if( msg == MAL_SUCCEED)
     698           0 :                                 msg = SQLrun(c,m);
     699           0 :                         resetMalBlk(c->curprg->def);
     700           0 :                         SQLremoveQueryFromCache(c);
     701             :                 }
     702           0 :                 rel_destroy(rel);
     703             :         }
     704           0 :         return RAcommit_statement(be, msg);
     705             : }
     706             : 
     707             : static char *
     708          31 : parseIdent(char *in, char *out)
     709             : {
     710         242 :         while (*in && *in != '"') {
     711         211 :                 if (*in == '\\' && (*(in + 1) == '\\' || *(in + 1) == '"')) {
     712           3 :                         *out++ = *(in + 1);
     713           3 :                         in+=2;
     714             :                 } else {
     715         208 :                         *out++ = *in++;
     716             :                 }
     717             :         }
     718          31 :         *out++ = '\0';
     719          31 :         return in;
     720             : }
     721             : 
     722             : struct local_var_entry {
     723             :         char *vname;
     724             :         sql_subtype tpe;
     725             : } local_var_entry;
     726             : 
     727             : struct global_var_entry {
     728             :         char *vname;
     729             :         sql_schema *s;
     730             : } global_var_entry;
     731             : 
     732             : static str
     733         185 : RAstatement2_return(backend *be, mvc *m, int nlevels, struct global_var_entry *gvars, int gentries, str msg)
     734             : {
     735         201 :         while (nlevels) { /* clean added frames */
     736          16 :                 stack_pop_frame(m);
     737          16 :                 nlevels--;
     738             :         }
     739         185 :         for (int i = 0 ; i < gentries ; i++) { /* clean any added global variables */
     740           0 :                 struct global_var_entry gv = gvars[i];
     741           0 :                 (void) remove_global_var(m, gv.s, gv.vname);
     742             :         }
     743         185 :         sa_reset(m->ta);
     744         185 :         return RAcommit_statement(be, msg);
     745             : }
     746             : 
     747             : static void
     748        1402 : subtype_from_string(mvc *sql, sql_subtype *st, char *type)
     749             : {
     750        1402 :         unsigned digits = 0, scale = 0;
     751             : 
     752        1402 :         char *end = strchr(type, '(');
     753        1402 :         if (end) {
     754          53 :                 end[0] = 0;
     755          53 :                 digits = strtol(end+1, &end, 10);
     756          53 :                 if (end && end[0] == ',')
     757           5 :                         scale = strtol(end+1, NULL, 10);
     758             :         }
     759        1402 :         if (!sql_find_subtype(st, type, digits, scale)) {
     760           2 :                 sql_type *t = mvc_bind_type(sql, type);
     761           2 :                 if (t)
     762           2 :                         sql_init_subtype(st, t, 0, 0);
     763             :         }
     764        1402 : }
     765             : 
     766             : str
     767         185 : RAstatement2(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     768             : {
     769         185 :         int pos = 0, nlevels = 0, *lkeys = NULL, lcap = 0, lentries = 0, gcap = 0, gentries = 0;
     770         185 :         str mod = *getArgReference_str(stk, pci, 1);
     771         185 :         str nme = *getArgReference_str(stk, pci, 2);
     772         185 :         str expr = *getArgReference_str(stk, pci, 3);
     773         185 :         str sig = *getArgReference_str(stk, pci, 4);
     774         185 :         str types = pci->argc == 6 ? *getArgReference_str(stk, pci, 5) : NULL;
     775         185 :         backend *be = NULL;
     776         185 :         mvc *m = NULL;
     777         185 :         str msg = MAL_SUCCEED;
     778         185 :         sql_rel *rel;
     779         185 :         list *refs, *ops;
     780         185 :         struct local_var_entry *lvars = NULL;
     781         185 :         struct global_var_entry *gvars = NULL;
     782             : 
     783         185 :         if ((msg = getSQLContext(cntxt, mb, &m, &be)) != NULL)
     784             :                 return msg;
     785         185 :         if ((msg = checkSQLContext(cntxt)) != NULL)
     786             :                 return msg;
     787         185 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED)
     788             :                 return msg;
     789         185 :         if (!m->sa)
     790         185 :                 m->sa = sa_create(m->pa);
     791         185 :         if (!m->sa)
     792           0 :                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     793             : 
     794         185 :         ops = sa_list(m->sa);
     795         213 :         while (sig && *sig) {
     796          28 :                 sql_schema *sh = NULL;
     797          28 :                 sql_type *t = NULL;
     798          28 :                 sql_subtype tpe;
     799          28 :                 char *p, *vtype = NULL, *sch = NULL, *var = NULL;
     800          28 :                 int d, s, level = strtol(sig, &p, 10);
     801             : 
     802          28 :                 var = p+1;
     803          28 :                 assert(*p == '"');
     804          28 :                 p = parseIdent(p+1, var);
     805          28 :                 p++;
     806          28 :                 if (*p == '"') { /* global variable, parse schema and name */
     807           3 :                         sch = var;
     808           3 :                         var = p+1;
     809           3 :                         p = parseIdent(p+1, var);
     810           3 :                         p++;
     811             :                 }
     812             : 
     813          28 :                 assert(*p == ' ');
     814          28 :                 p++; /* skip space and get type */
     815          28 :                 vtype = p;
     816          28 :                 p = strchr(p, '(');
     817          28 :                 *p++ = '\0';
     818             : 
     819             :                 /* get digits and scale */
     820          28 :                 d = strtol(p, &p, 10);
     821          28 :                 p++; /* skip , */
     822          28 :                 s = strtol(p, &p, 10);
     823          28 :                 p+=2; /* skip ) and , or ' ' */
     824          28 :                 sig = p;
     825             : 
     826          28 :                 if (!sql_find_subtype(&tpe, vtype, d, s)) {
     827           6 :                         if (!(t = mvc_bind_type(m, vtype))) /* try an external type */
     828           0 :                                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(42000) "SQL type %s(%d, %d) not found\n", vtype, d, s));
     829           6 :                         sql_init_subtype(&tpe, t, d, s);
     830             :                 }
     831             : 
     832          28 :                 if (sch) {
     833           3 :                         assert(level == 0);
     834           3 :                         if (!(sh = mvc_bind_schema(m, sch)))
     835           0 :                                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(3F000) "No such schema '%s'", sch));
     836           3 :                         if (!find_global_var(m, sh, var)) { /* don't add the same global variable again */
     837           0 :                                 if (!push_global_var(m, sch, var, &tpe)) /* if doesn't exist, add it, then remove it before returning */
     838           0 :                                         return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     839           0 :                                 if (gentries == gcap) {
     840           0 :                                         if (gcap == 0) {
     841           0 :                                                 gcap = 8;
     842           0 :                                                 gvars = SA_NEW_ARRAY(m->ta, struct global_var_entry, gcap);
     843             :                                         } else {
     844           0 :                                                 int ngcap = gcap * 4;
     845           0 :                                                 gvars = SA_RENEW_ARRAY(m->ta, struct global_var_entry, gvars, ngcap, gcap);
     846             :                                                 gcap = ngcap;
     847             :                                         }
     848           0 :                                         gvars[gentries++] = (struct global_var_entry) {.s = sh, .vname = var,};
     849             :                                 }
     850             :                         }
     851           3 :                         list_append(ops, exp_var(m->sa, sa_strdup(m->sa, sch), sa_strdup(m->sa, var), &tpe, 0));
     852             :                 } else {
     853          25 :                         char opname[BUFSIZ];
     854             : 
     855          25 :                         if (lentries == lcap) {
     856          13 :                                 if (lcap == 0) {
     857          13 :                                         lcap = 8;
     858          13 :                                         lkeys = SA_NEW_ARRAY(m->ta, int, lcap);
     859          13 :                                         lvars = SA_NEW_ARRAY(m->ta, struct local_var_entry, lcap);
     860             :                                 } else {
     861           0 :                                         int nlcap = lcap * 4;
     862           0 :                                         lkeys = SA_RENEW_ARRAY(m->ta, int, lkeys, nlcap, lcap);
     863           0 :                                         lvars = SA_RENEW_ARRAY(m->ta, struct local_var_entry, lvars, nlcap, lcap);
     864             :                                         lcap = nlcap;
     865             :                                 }
     866             :                         }
     867          25 :                         lkeys[lentries] = level;
     868          25 :                         lvars[lentries] = (struct local_var_entry) {.tpe = tpe, .vname = var,};
     869          25 :                         lentries++;
     870             : 
     871          25 :                         snprintf(opname, BUFSIZ, "%d%%%s", level, var); /* engineering trick */
     872          25 :                         list_append(ops, exp_var(m->sa, NULL, sa_strdup(m->sa, opname), &tpe, level));
     873             :                 }
     874             :         }
     875         185 :         if (lentries) {
     876          13 :                 GDKqsort(lkeys, lvars, NULL, lentries, sizeof(int), sizeof(struct local_var_entry), TYPE_int, false, false);
     877             : 
     878          38 :                 for (int i = 0 ; i < lentries ; i++) {
     879          25 :                         int next_level = lkeys[i];
     880          25 :                         struct local_var_entry next_val = lvars[i];
     881             : 
     882          25 :                         assert(next_level != 0); /* no global variables here */
     883          41 :                         while (nlevels < next_level) { /* add gap levels */
     884          16 :                                 if (!stack_push_frame(m, NULL))
     885           0 :                                         return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     886          16 :                                 nlevels++;
     887             :                         }
     888          25 :                         if (!frame_push_var(m, next_val.vname, &next_val.tpe))
     889           0 :                                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     890             :                 }
     891             :         }
     892             : 
     893         185 :         refs = sa_list(m->sa);
     894         185 :         rel = rel_read(m, expr, &pos, refs);
     895         185 :         if (rel)
     896         181 :                 rel = sql_processrelation(m, rel, 0, 1, 0, 0);
     897         181 :         if (!rel) {
     898           4 :                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     899           4 :                         msg = createException(SQL, "RAstatement2", "%s", m->errstr);
     900             :                 else
     901           0 :                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "%s", m->errstr);
     902         181 :         } else if (rel && types && is_simple_project(rel->op)) { /* Test if types match */
     903         181 :                 list *types_list = sa_list(m->sa);
     904         180 :                 str token, rest;
     905             : 
     906        1582 :                 for (token = strtok_r(types, "%", &rest); token; token = strtok_r(NULL, "%", &rest))
     907        1402 :                         list_append(types_list, token);
     908             : 
     909         181 :                 if (list_length(types_list) != list_length(rel->exps))
     910           0 :                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "The number of projections don't match between the generated plan and the expected one: %d != %d",
     911             :                                                                   list_length(types_list), list_length(rel->exps));
     912             :                 else {
     913         181 :                         int i = 1;
     914        1583 :                         for (node *n = rel->exps->h, *m = types_list->h ; n && m && !msg ; n = n->next, m = m->next) {
     915        1402 :                                 sql_exp *e = n->data, *ne = NULL;
     916        1402 :                                 sql_subtype *t = exp_subtype(e), et;
     917             : 
     918        1402 :                                 subtype_from_string(be->mvc, &et, m->data);
     919        1402 :                                 if (!is_subtype(t, &et) && (ne = exp_check_type(be->mvc, &et, rel, e, type_equal)) == NULL) {
     920           0 :                                         str got = sql_subtype_string(be->mvc->ta, t), expected = (str) m->data;
     921           0 :                                         if (!got)
     922           0 :                                                 msg = createException(SQL, "RAstatement2", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     923           0 :                                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "Parameter %d has wrong SQL type, expected %s, but got %s instead", i, expected, got);
     924             :                                 }
     925           0 :                                 if (ne) {
     926           3 :                                         exp_setname(be->mvc, ne, exp_relname(e), exp_name(e));
     927           3 :                                         n->data = ne;
     928             :                                 }
     929        1402 :                                 i++;
     930             :                         }
     931             :                 }
     932             :         }
     933         185 :         if (!msg && monet5_create_relational_function(m, mod, nme, rel, NULL, ops, 0) < 0)
     934           0 :                 msg = createException(SQL, "RAstatement2", "%s", m->errstr);
     935         185 :         rel_destroy(rel);
     936         185 :         return RAstatement2_return(be, m, nlevels, gvars, gentries, msg);
     937             : }
     938             : 
     939             : str
     940         185 : RAstatementEnd(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     941             : {
     942         185 :         backend *be = NULL;
     943         185 :         mvc *m = NULL;
     944         185 :         str msg = MAL_SUCCEED;
     945             : 
     946         185 :         (void) stk;
     947         185 :         (void) pci;
     948         185 :         if ((msg = getSQLContext(cntxt, mb, &m, &be)) != NULL)
     949             :                 return msg;
     950         185 :         if ((msg = checkSQLContext(cntxt)) != NULL)
     951             :                 return msg;
     952             : 
     953         185 :         sqlcleanup(be, 0);
     954         185 :         return SQLautocommit(m);
     955             : }

Generated by: LCOV version 1.14