LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_execute.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 443 581 76.2 %
Date: 2024-04-25 20:03:45 Functions: 10 12 83.3 %

          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 colum 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,"clob");
     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 :         renameVariables(mb);
     253           4 :         return msg;
     254             : }
     255             : 
     256             : str
     257      543723 : SQLrun(Client c, mvc *m)
     258             : {
     259      543723 :         str msg = MAL_SUCCEED;
     260      543723 :         MalBlkPtr mb = c->curprg->def;
     261             : 
     262      543723 :         assert(!*m->errstr);
     263             : 
     264      543723 :         TRC_INFO(SQL_EXECUTION, "Executing: %s", c->query);
     265      543725 :         MT_thread_setworking(c->query);
     266             : 
     267      543724 :         if (m->emod & mod_explain) {
     268          63 :                 if (c->curprg->def)
     269          63 :                         printFunction(c->fdout, mb, 0, LIST_MAL_NAME | LIST_MAL_VALUE  | LIST_MAL_TYPE |  LIST_MAL_MAPI);
     270             :         } else {
     271      543661 :                 if (m->emod & mod_trace){
     272           4 :                         if((msg = SQLsetTrace(c,mb)) == MAL_SUCCEED) {
     273           4 :                                 setVariableScope(mb);
     274           4 :                                 MT_lock_set(&mal_contextLock);
     275           4 :                                 c->idle = 0;
     276           4 :                                 c->lastcmd = time(0);
     277           4 :                                 MT_lock_unset(&mal_contextLock);
     278           4 :                                 msg = runMAL(c, mb, 0, 0);
     279           4 :                                 stopTrace(c);
     280             :                         }
     281             :                 } else {
     282      543657 :                         setVariableScope(mb);
     283      543657 :                         MT_lock_set(&mal_contextLock);
     284      543657 :                         c->idle = 0;
     285      543657 :                         c->lastcmd = time(0);
     286      543657 :                         MT_lock_unset(&mal_contextLock);
     287      543657 :                         msg = runMAL(c, mb, 0, 0);
     288             :                 }
     289      543661 :                 resetMalBlk(mb);
     290             :         }
     291             :         /* after the query has been finished we enter the idle state */
     292      543708 :         MT_lock_set(&mal_contextLock);
     293      543724 :         c->idle = time(0);
     294      543724 :         c->lastcmd = 0;
     295      543724 :         MT_lock_unset(&mal_contextLock);
     296      543724 :         MT_thread_setworking(NULL);
     297      543724 :         return msg;
     298             : }
     299             : 
     300             : /*
     301             :  * Escape single quotes and backslashes. This is important to do before calling
     302             :  * SQLstatementIntern, if we are pasting user provided strings into queries
     303             :  * passed to the SQLstatementIntern. Otherwise we open ourselves to SQL
     304             :  * injection attacks.
     305             :  *
     306             :  * It returns the input string with all the single quotes(') and the backslashes
     307             :  * (\) doubled, or NULL, if it could not allocate enough space.
     308             :  *
     309             :  * The caller is responsible to free the returned value.
     310             :  */
     311             : str
     312           0 : SQLescapeString(str s)
     313             : {
     314           0 :         str ret = NULL;
     315           0 :         char *p, *q;
     316           0 :         size_t len = 0;
     317             : 
     318           0 :         if(!s) {
     319             :                 return NULL;
     320             :         }
     321             : 
     322             :         /* At most we will need 2*strlen(s) + 1 characters */
     323           0 :         len = strlen(s);
     324           0 :         ret = (str)GDKmalloc(2*len + 1);
     325           0 :         if (!ret) {
     326             :                 return NULL;
     327             :         }
     328             : 
     329           0 :         for (p = s, q = ret; *p != '\0'; p++, q++) {
     330           0 :                 *q = *p;
     331           0 :                 if (*p == '\'') {
     332           0 :                         *(++q) = '\'';
     333             :                 }
     334           0 :                 else if (*p == '\\') {
     335           0 :                         *(++q) = '\\';
     336             :                 }
     337             :         }
     338             : 
     339           0 :         *q = '\0';
     340           0 :         return ret;
     341             : }
     342             : 
     343             : str
     344       10764 : SQLstatementIntern(Client c, const char *expr, const char *nme, bit execute, bit output, res_table **result)
     345             : {
     346       10764 :         int status = 0, err = 0, oldvtop, oldstop = 1, oldvid, inited = 0, ac, sizeframes, topframes;
     347       10764 :         unsigned int label;
     348       10764 :         mvc *o = NULL, *m = NULL;
     349       10764 :         sql_frame **frames;
     350       10764 :         list *global_vars;
     351       10764 :         buffer *b = NULL;
     352       10764 :         char *n = NULL;
     353       10764 :         bstream *bs = NULL;
     354       10764 :         stream *buf = NULL;
     355       10764 :         str msg = MAL_SUCCEED;
     356       10764 :         backend *be = NULL, *sql = (backend *) c->sqlcontext;
     357       10764 :         Symbol backup = NULL;
     358       10764 :         size_t len = strlen(expr);
     359             : 
     360       10764 :         if (!sql) {
     361           9 :                 inited = 1;
     362           9 :                 msg = SQLinitClient(c, NULL, NULL, NULL);
     363           9 :                 sql = (backend *) c->sqlcontext;
     364             :         }
     365       10764 :         if (msg){
     366           0 :                 freeException(msg);
     367           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY002) "Catalogue not available");
     368             :         }
     369             : 
     370       10764 :         m = sql->mvc;
     371       10764 :         ac = m->session->auto_commit;
     372       10764 :         o = MNEW(mvc);
     373       10764 :         if (!o) {
     374           0 :                 if (inited) {
     375           0 :                         msg = SQLresetClient(c);
     376           0 :                         freeException(msg);
     377             :                 }
     378           0 :                 throw(SQL, "sql.statement", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     379             :         }
     380       10764 :         *o = *m;
     381             : 
     382             :         /* create private allocator */
     383       10764 :         m->sa = NULL;
     384       10764 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED) {
     385           0 :                 be = sql;
     386           0 :                 sql = NULL;
     387           0 :                 goto endofcompile;
     388             :         }
     389       10764 :         status = m->session->status;
     390             : 
     391       10764 :         m->type = Q_PARSE;
     392       10764 :         be = sql;
     393       10764 :         sql = backend_create(m, c);
     394       10764 :         if (sql == NULL) {
     395           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     396           0 :                 goto endofcompile;
     397             :         }
     398       10764 :         sql->output_format = be->output_format;
     399       10764 :         if (!output) {
     400       10752 :                 sql->output_format = OFMT_NONE;
     401             :         }
     402       10764 :         sql->depth++;
     403             : 
     404       10764 :         m->user_id = m->role_id = USER_MONETDB;
     405       10764 :         if (result)
     406        1628 :                 m->reply_size = -2; /* do not clean up result tables */
     407             : 
     408             :         /* mimic a client channel on which the query text is received */
     409       10764 :         b = malloc(sizeof(buffer));
     410       10764 :         if (b == NULL) {
     411           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     412           0 :                 goto endofcompile;
     413             :         }
     414       10764 :         n = malloc(len + 1 + 1);
     415       10764 :         if (n == NULL) {
     416           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     417           0 :                 goto endofcompile;
     418             :         }
     419       10764 :         strcpy_len(n, expr, len + 1);
     420       10764 :         n[len] = '\n';
     421       10764 :         n[len + 1] = 0;
     422       10764 :         len++;
     423       10764 :         buffer_init(b, n, len);
     424       10764 :         buf = buffer_rastream(b, "sqlstatement");
     425       10764 :         if (buf == NULL) {
     426           0 :                 buffer_destroy(b); /* n and b will be freed by the buffer */
     427           0 :                 b = NULL;
     428           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     429           0 :                 goto endofcompile;
     430             :         }
     431       10764 :         bs = bstream_create(buf, b->len);
     432       10764 :         if (bs == NULL) {
     433           0 :                 mnstr_destroy(buf);
     434           0 :                 buffer_destroy(b);
     435           0 :                 b = NULL;
     436           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     437           0 :                 goto endofcompile;
     438             :         }
     439       10764 :         scanner_init(&m->scanner, bs, NULL);
     440       10764 :         m->scanner.mode = LINE_N;
     441       10764 :         bstream_next(m->scanner.rs);
     442             : 
     443       10764 :         m->params = NULL;
     444       10764 :         m->session->auto_commit = 0;
     445       10764 :         if (!m->sa && !(m->sa = sa_create(m->pa)) ) {
     446           0 :                 msg = createException(SQL,"sql.statement",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     447           0 :                 goto endofcompile;
     448             :         }
     449             : 
     450             :         /*
     451             :          * System has been prepared to parse it and generate code.
     452             :          * Scan the complete string for SQL statements, stop at the first error.
     453             :          */
     454       10764 :         c->sqlcontext = sql;
     455       10764 :         if (c->curprg) {
     456       10742 :                 backup = c->curprg;
     457       10742 :                 c->curprg = NULL;
     458             :         }
     459             : 
     460      304300 :         while (msg == MAL_SUCCEED && m->scanner.rs->pos < m->scanner.rs->len) {
     461      293542 :                 sql_rel *r;
     462             : 
     463      293542 :                 m->sym = NULL;
     464      587084 :                 if ((err = sqlparse(m)) ||
     465             :                     /* Only forget old errors on transaction boundaries */
     466      587084 :                     (mvc_status(m) && m->type != Q_TRANS) || !m->sym) {
     467           2 :                         if (!err)
     468           2 :                                 err = mvc_status(m);
     469           2 :                         if (*m->errstr){
     470           0 :                                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     471           0 :                                         msg = createException(PARSE, "SQLparser", "%s", m->errstr);
     472             :                                 else
     473           0 :                                         msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
     474           0 :                                 *m->errstr = 0;
     475             :                         }
     476           2 :                         sqlcleanup(sql, err);
     477           2 :                         execute = 0;
     478           2 :                         if (!err)
     479           2 :                                 continue;
     480           0 :                         goto endofcompile;
     481             :                 }
     482             : 
     483             :                 /*
     484             :                  * We have dealt with the first parsing step and advanced the input reader
     485             :                  * to the next statement (if any).
     486             :                  * Now is the time to also perform the semantic analysis,
     487             :                  * optimize and produce code.
     488             :                  * We don't search the cache for a previous incarnation yet.
     489             :                  */
     490      293540 :                 if((msg = MSinitClientPrg(c, sql_private_module_name, nme)) != MAL_SUCCEED) {
     491           0 :                         goto endofcompile;
     492             :                 }
     493      293540 :                 oldvtop = c->curprg->def->vtop;
     494      293540 :                 oldstop = c->curprg->def->stop;
     495      293540 :                 oldvid = c->curprg->def->vid;
     496      293540 :                 r = sql_symbol2relation(sql, m->sym);
     497             : 
     498      293540 :                 assert(m->emode != m_prepare);
     499      293540 :                 scanner_query_processed(&(m->scanner));
     500      293540 :                 if ((err = mvc_status(m)) ) {
     501           6 :                         if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     502           6 :                                 msg = createException(PARSE, "SQLparser", "%s", m->errstr);
     503             :                         else
     504           0 :                                 msg = createException(PARSE, "SQLparser", SQLSTATE(42000) "%s", m->errstr);
     505           6 :                         *m->errstr = 0;
     506           6 :                         msg = handle_error(m, status, msg);
     507           6 :                         sqlcleanup(sql, err);
     508             :                         /* restore the state */
     509           6 :                         MSresetInstructions(c->curprg->def, oldstop);
     510           6 :                         freeVariables(c, c->curprg->def, c->glb, oldvtop, oldvid);
     511           6 :                         c->curprg->def->errors = 0;
     512           6 :                         goto endofcompile;
     513             :                 }
     514             :                 /* generate MAL code */
     515      293534 :                 be->depth++;
     516      293534 :                 setVarType(c->curprg->def, 0, 0);
     517      293534 :                 if (backend_dumpstmt(be, c->curprg->def, r, 1, 1, NULL) < 0)
     518           0 :                         err = 1;
     519      293534 :                 be->depth--;
     520             : 
     521      293534 :                 if (err == 0) {
     522      293534 :                         if (msg == MAL_SUCCEED)
     523      293534 :                                 msg = SQLoptimizeQuery(c, c->curprg->def);
     524      293534 :                         if (msg)
     525             :                                 err = 1;
     526             :                 }
     527             : 
     528      293534 :                 if (err) {
     529           0 :                         status = -10;
     530           0 :                         if (msg)
     531           0 :                                 msg = handle_error(m, status, msg);
     532           0 :                         sqlcleanup(sql, err);
     533             :                         /* restore the state */
     534           0 :                         MSresetInstructions(c->curprg->def, oldstop);
     535           0 :                         freeVariables(c, c->curprg->def, c->glb, oldvtop, oldvid);
     536           0 :                         c->curprg->def->errors = 0;
     537           0 :                         goto endofcompile;
     538             :                 }
     539             : 
     540      293534 :                 if (execute) {
     541      293534 :                         if (!output)
     542      293522 :                                 sql->out = NULL;     /* no output stream */
     543      293534 :                         be->depth++;
     544      293534 :                         msg = SQLrun(c,m);
     545      293534 :                         be->depth--;
     546      293534 :                         MSresetInstructions(c->curprg->def, oldstop);
     547      293534 :                         freeVariables(c, c->curprg->def, NULL, oldvtop, oldvid);
     548      293534 :                         sqlcleanup(sql, 0);
     549      293534 :                         if (!execute)
     550             :                                 goto endofcompile;
     551             :                 }
     552      293534 :                 if (sql->results) {
     553        1588 :                         if (result) { /* return all results sets */
     554        1587 :                                 *result = sql->results;
     555             :                         } else {
     556           1 :                                 if (sql->results == be->results)
     557           0 :                                         be->results = NULL;
     558           1 :                                 res_tables_destroy(sql->results);
     559             :                         }
     560        1588 :                         sql->results = NULL;
     561             :                 }
     562             :         }
     563             : /*
     564             :  * We are done; a MAL procedure resides in the cache.
     565             :  */
     566       10758 : endofcompile:
     567       10764 :         if (execute)
     568       10762 :                 MSresetInstructions(c->curprg->def, 1);
     569             : 
     570       10764 :         if (backup)
     571       10742 :                 c->curprg = backup;
     572             : 
     573       10764 :         c->sqlcontext = be;
     574       10764 :         backend_destroy(sql);
     575       10764 :         buffer_destroy(b);
     576       10764 :         bstream_destroy(m->scanner.rs);
     577       10764 :         if (m->sa)
     578       10764 :                 sa_destroy(m->sa);
     579       10764 :         m->sa = NULL;
     580       10764 :         m->sym = NULL;
     581       10764 :         m->runs = NULL;
     582             :         /* variable stack maybe resized, ie we need to keep the new stack */
     583       10764 :         label = m->label;
     584       10764 :         status = m->session->status;
     585       10764 :         global_vars = m->global_vars;
     586       10764 :         sizeframes = m->sizeframes;
     587       10764 :         topframes = m->topframes;
     588       10764 :         frames = m->frames;
     589       10764 :         *m = *o;
     590       10764 :         _DELETE(o);
     591       10764 :         m->label = label;
     592       10764 :         m->global_vars = global_vars;
     593       10764 :         m->sizeframes = sizeframes;
     594       10764 :         m->topframes = topframes;
     595       10764 :         m->frames = frames;
     596       10764 :         m->session->status = status;
     597       10764 :         m->session->auto_commit = ac;
     598       10764 :         if (inited) {
     599           9 :                 str other = SQLresetClient(c);
     600           9 :                 freeException(other);
     601             :         }
     602             :         return msg;
     603             : }
     604             : 
     605             : str
     606      250189 : SQLengineIntern(Client c, backend *be)
     607             : {
     608      250189 :         str msg = MAL_SUCCEED;
     609             :         //char oldlang = be->language;
     610      250189 :         mvc *m = be->mvc;
     611             : 
     612      250189 :         assert (m->emode != m_deallocate && m->emode != m_prepare);
     613      250189 :         assert (c->curprg->def->stop > 2);
     614             : 
     615             :         //be->language = 'D';
     616      250189 :         if (MALcommentsOnly(c->curprg->def))
     617             :                 msg = MAL_SUCCEED;
     618             :         else
     619      250189 :                 msg = SQLrun(c,m);
     620             : 
     621      250189 :         if (m->type == Q_SCHEMA && m->qc != NULL)
     622       15985 :                 qc_clean(m->qc);
     623      250189 :         be->q = NULL;
     624      250189 :         if (msg)
     625       17654 :                 m->session->status = -10;
     626      250189 :         sqlcleanup(be, (!msg) ? 0 : -1);
     627      250189 :         MSresetInstructions(c->curprg->def, 1);
     628      250187 :         freeVariables(c, c->curprg->def, NULL, be->vtop, be->vid);
     629             :         //be->language = oldlang;
     630             :         /*
     631             :          * Any error encountered during execution should block further processing
     632             :          * unless auto_commit has been set.
     633             :          */
     634      250189 :         return msg;
     635             : }
     636             : 
     637             : void
     638          33 : SQLdestroyResult(res_table *destroy)
     639             : {
     640          33 :         res_table_destroy(destroy);
     641          33 : }
     642             : 
     643             : static str
     644         184 : RAcommit_statement(backend *be, str msg)
     645             : {
     646         184 :         mvc *m = be->mvc;
     647             :         /* if an error already exists set the session status to dirty */
     648         184 :         if (msg != MAL_SUCCEED && m->session->tr->active && !m->session->status)
     649           2 :                 m->session->status = -1;
     650         184 :         return msg;
     651             : }
     652             : 
     653             : /* a hook is provided to execute relational algebra expressions */
     654             : str
     655           0 : RAstatement(Client c, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     656             : {
     657           0 :         int pos = 0;
     658           0 :         str *expr = getArgReference_str(stk, pci, 1);
     659           0 :         bit *opt = getArgReference_bit(stk, pci, 2);
     660           0 :         backend *be = NULL;
     661           0 :         mvc *m = NULL;
     662           0 :         str msg = MAL_SUCCEED;
     663           0 :         sql_rel *rel;
     664           0 :         list *refs;
     665             : 
     666           0 :         if ((msg = getSQLContext(c, mb, &m, &be)) != NULL)
     667             :                 return msg;
     668           0 :         if ((msg = checkSQLContext(c)) != NULL)
     669             :                 return msg;
     670           0 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED)
     671             :                 return msg;
     672           0 :         if (!m->sa)
     673           0 :                 m->sa = sa_create(m->pa);
     674           0 :         if (!m->sa)
     675           0 :                 return RAcommit_statement(be, createException(SQL,"RAstatement",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     676           0 :         refs = sa_list(m->sa);
     677           0 :         rel = rel_read(m, *expr, &pos, refs);
     678           0 :         if (*opt && rel)
     679           0 :                 rel = sql_processrelation(m, rel, 0, 0, 0, 0);
     680           0 :         if (!rel) {
     681           0 :                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     682           0 :                         msg = createException(SQL, "RAstatement", "%s", m->errstr);
     683             :                 else
     684           0 :                         msg = createException(SQL, "RAstatement", SQLSTATE(42000) "%s", m->errstr);
     685             :         } else {
     686           0 :                 if ((msg = MSinitClientPrg(c, sql_private_module_name, "test")) != MAL_SUCCEED)
     687           0 :                         return RAcommit_statement(be, msg);
     688             : 
     689             :                 /* generate MAL code, ignoring any code generation error */
     690           0 :                 setVarType(c->curprg->def, 0, 0);
     691           0 :                 if (backend_dumpstmt(be, c->curprg->def, rel, 0, 1, NULL) < 0) {
     692           0 :                         msg = createException(SQL,"RAstatement","Program contains errors"); // TODO: use macro definition.
     693             :                 } else {
     694           0 :                         SQLaddQueryToCache(c);
     695           0 :                         msg = SQLoptimizeFunction(c,c->curprg->def);
     696           0 :                         if( msg == MAL_SUCCEED)
     697           0 :                                 msg = SQLrun(c,m);
     698           0 :                         resetMalBlk(c->curprg->def);
     699           0 :                         SQLremoveQueryFromCache(c);
     700             :                 }
     701           0 :                 rel_destroy(rel);
     702             :         }
     703           0 :         return RAcommit_statement(be, msg);
     704             : }
     705             : 
     706             : static char *
     707          31 : parseIdent(char *in, char *out)
     708             : {
     709         242 :         while (*in && *in != '"') {
     710         211 :                 if (*in == '\\' && (*(in + 1) == '\\' || *(in + 1) == '"')) {
     711           3 :                         *out++ = *(in + 1);
     712           3 :                         in+=2;
     713             :                 } else {
     714         208 :                         *out++ = *in++;
     715             :                 }
     716             :         }
     717          31 :         *out++ = '\0';
     718          31 :         return in;
     719             : }
     720             : 
     721             : struct local_var_entry {
     722             :         char *vname;
     723             :         sql_subtype tpe;
     724             : } local_var_entry;
     725             : 
     726             : struct global_var_entry {
     727             :         char *vname;
     728             :         sql_schema *s;
     729             : } global_var_entry;
     730             : 
     731             : static str
     732         184 : RAstatement2_return(backend *be, mvc *m, int nlevels, struct global_var_entry *gvars, int gentries, str msg)
     733             : {
     734         200 :         while (nlevels) { /* clean added frames */
     735          16 :                 stack_pop_frame(m);
     736          16 :                 nlevels--;
     737             :         }
     738         184 :         for (int i = 0 ; i < gentries ; i++) { /* clean any added global variables */
     739           0 :                 struct global_var_entry gv = gvars[i];
     740           0 :                 (void) remove_global_var(m, gv.s, gv.vname);
     741             :         }
     742         184 :         sa_reset(m->ta);
     743         184 :         return RAcommit_statement(be, msg);
     744             : }
     745             : 
     746             : str
     747         184 : RAstatement2(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     748             : {
     749         184 :         int pos = 0, nlevels = 0, *lkeys = NULL, lcap = 0, lentries = 0, gcap = 0, gentries = 0;
     750         184 :         str mod = *getArgReference_str(stk, pci, 1);
     751         184 :         str nme = *getArgReference_str(stk, pci, 2);
     752         184 :         str expr = *getArgReference_str(stk, pci, 3);
     753         184 :         str sig = *getArgReference_str(stk, pci, 4);
     754         184 :         str types = pci->argc == 6 ? *getArgReference_str(stk, pci, 5) : NULL;
     755         184 :         backend *be = NULL;
     756         184 :         mvc *m = NULL;
     757         184 :         str msg = MAL_SUCCEED;
     758         184 :         sql_rel *rel;
     759         184 :         list *refs, *ops;
     760         184 :         struct local_var_entry *lvars = NULL;
     761         184 :         struct global_var_entry *gvars = NULL;
     762             : 
     763         184 :         if ((msg = getSQLContext(cntxt, mb, &m, &be)) != NULL)
     764             :                 return msg;
     765         184 :         if ((msg = checkSQLContext(cntxt)) != NULL)
     766             :                 return msg;
     767         184 :         if ((msg = SQLtrans(m)) != MAL_SUCCEED)
     768             :                 return msg;
     769         184 :         if (!m->sa)
     770         184 :                 m->sa = sa_create(m->pa);
     771         184 :         if (!m->sa)
     772           0 :                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     773             : 
     774         184 :         ops = sa_list(m->sa);
     775         212 :         while (sig && *sig) {
     776          28 :                 sql_schema *sh = NULL;
     777          28 :                 sql_type *t = NULL;
     778          28 :                 sql_subtype tpe;
     779          28 :                 char *p, *vtype = NULL, *sch = NULL, *var = NULL;
     780          28 :                 int d, s, level = strtol(sig, &p, 10);
     781             : 
     782          28 :                 var = p+1;
     783          28 :                 assert(*p == '"');
     784          28 :                 p = parseIdent(p+1, var);
     785          28 :                 p++;
     786          28 :                 if (*p == '"') { /* global variable, parse schema and name */
     787           3 :                         sch = var;
     788           3 :                         var = p+1;
     789           3 :                         p = parseIdent(p+1, var);
     790           3 :                         p++;
     791             :                 }
     792             : 
     793          28 :                 assert(*p == ' ');
     794          28 :                 p++; /* skip space and get type */
     795          28 :                 vtype = p;
     796          28 :                 p = strchr(p, '(');
     797          28 :                 *p++ = '\0';
     798             : 
     799             :                 /* get digits and scale */
     800          28 :                 d = strtol(p, &p, 10);
     801          28 :                 p++; /* skip , */
     802          28 :                 s = strtol(p, &p, 10);
     803          28 :                 p+=2; /* skip ) and , or ' ' */
     804          28 :                 sig = p;
     805             : 
     806          28 :                 if (!sql_find_subtype(&tpe, vtype, d, s)) {
     807           6 :                         if (!(t = mvc_bind_type(m, vtype))) /* try an external type */
     808           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));
     809           6 :                         sql_init_subtype(&tpe, t, d, s);
     810             :                 }
     811             : 
     812          28 :                 if (sch) {
     813           3 :                         assert(level == 0);
     814           3 :                         if (!(sh = mvc_bind_schema(m, sch)))
     815           0 :                                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(3F000) "No such schema '%s'", sch));
     816           3 :                         if (!find_global_var(m, sh, var)) { /* don't add the same global variable again */
     817           0 :                                 if (!push_global_var(m, sch, var, &tpe)) /* if doesn't exist, add it, then remove it before returning */
     818           0 :                                         return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     819           0 :                                 if (gentries == gcap) {
     820           0 :                                         if (gcap == 0) {
     821           0 :                                                 gcap = 8;
     822           0 :                                                 gvars = SA_NEW_ARRAY(m->ta, struct global_var_entry, gcap);
     823             :                                         } else {
     824           0 :                                                 int ngcap = gcap * 4;
     825           0 :                                                 gvars = SA_RENEW_ARRAY(m->ta, struct global_var_entry, gvars, ngcap, gcap);
     826             :                                                 gcap = ngcap;
     827             :                                         }
     828           0 :                                         gvars[gentries++] = (struct global_var_entry) {.s = sh, .vname = var,};
     829             :                                 }
     830             :                         }
     831           3 :                         list_append(ops, exp_var(m->sa, sa_strdup(m->sa, sch), sa_strdup(m->sa, var), &tpe, 0));
     832             :                 } else {
     833          25 :                         char opname[BUFSIZ];
     834             : 
     835          25 :                         if (lentries == lcap) {
     836          13 :                                 if (lcap == 0) {
     837          13 :                                         lcap = 8;
     838          13 :                                         lkeys = SA_NEW_ARRAY(m->ta, int, lcap);
     839          13 :                                         lvars = SA_NEW_ARRAY(m->ta, struct local_var_entry, lcap);
     840             :                                 } else {
     841           0 :                                         int nlcap = lcap * 4;
     842           0 :                                         lkeys = SA_RENEW_ARRAY(m->ta, int, lkeys, nlcap, lcap);
     843           0 :                                         lvars = SA_RENEW_ARRAY(m->ta, struct local_var_entry, lvars, nlcap, lcap);
     844             :                                         lcap = nlcap;
     845             :                                 }
     846             :                         }
     847          25 :                         lkeys[lentries] = level;
     848          25 :                         lvars[lentries] = (struct local_var_entry) {.tpe = tpe, .vname = var,};
     849          25 :                         lentries++;
     850             : 
     851          25 :                         snprintf(opname, BUFSIZ, "%d%%%s", level, var); /* engineering trick */
     852          25 :                         list_append(ops, exp_var(m->sa, NULL, sa_strdup(m->sa, opname), &tpe, level));
     853             :                 }
     854             :         }
     855         184 :         if (lentries) {
     856          13 :                 GDKqsort(lkeys, lvars, NULL, lentries, sizeof(int), sizeof(struct local_var_entry), TYPE_int, false, false);
     857             : 
     858          38 :                 for (int i = 0 ; i < lentries ; i++) {
     859          25 :                         int next_level = lkeys[i];
     860          25 :                         struct local_var_entry next_val = lvars[i];
     861             : 
     862          25 :                         assert(next_level != 0); /* no global variables here */
     863          41 :                         while (nlevels < next_level) { /* add gap levels */
     864          16 :                                 if (!stack_push_frame(m, NULL))
     865           0 :                                         return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     866          16 :                                 nlevels++;
     867             :                         }
     868          25 :                         if (!frame_push_var(m, next_val.vname, &next_val.tpe))
     869           0 :                                 return RAstatement2_return(be, m, nlevels, gvars, gentries, createException(SQL,"RAstatement2",SQLSTATE(HY013) MAL_MALLOC_FAIL));
     870             :                 }
     871             :         }
     872             : 
     873         184 :         refs = sa_list(m->sa);
     874         184 :         rel = rel_read(m, expr, &pos, refs);
     875         184 :         if (rel)
     876         180 :                 rel = sql_processrelation(m, rel, 0, 0, 0, 0);
     877         180 :         if (!rel) {
     878           4 :                 if (strlen(m->errstr) > 6 && m->errstr[5] == '!')
     879           4 :                         msg = createException(SQL, "RAstatement2", "%s", m->errstr);
     880             :                 else
     881           0 :                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "%s", m->errstr);
     882         180 :         } else if (rel && types && is_simple_project(rel->op)) { /* Test if types match */
     883         180 :                 list *types_list = sa_list(m->sa);
     884         180 :                 str token, rest;
     885             : 
     886        1579 :                 for (token = strtok_r(types, "%", &rest); token; token = strtok_r(NULL, "%", &rest))
     887        1399 :                         list_append(types_list, token);
     888             : 
     889         180 :                 if (list_length(types_list) != list_length(rel->exps))
     890           0 :                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "The number of projections don't match between the generated plan and the expected one: %d != %d",
     891             :                                                                   list_length(types_list), list_length(rel->exps));
     892             :                 else {
     893         180 :                         int i = 1;
     894        1579 :                         for (node *n = rel->exps->h, *m = types_list->h ; n && m && !msg ; n = n->next, m = m->next) {
     895        1399 :                                 sql_exp *e = (sql_exp *) n->data;
     896        1399 :                                 sql_subtype *t = exp_subtype(e);
     897        1399 :                                 str got = sql_subtype_string(be->mvc->ta, t), expected = (str) m->data;
     898             : 
     899        1399 :                                 if (!got)
     900           0 :                                         msg = createException(SQL, "RAstatement2", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     901        1399 :                                 else if (strcmp(expected, got) != 0)
     902           2 :                                         msg = createException(SQL, "RAstatement2", SQLSTATE(42000) "Parameter %d has wrong SQL type, expected %s, but got %s instead", i, expected, got);
     903        1399 :                                 i++;
     904             :                         }
     905             :                 }
     906             :         }
     907         184 :         if (!msg && monet5_create_relational_function(m, mod, nme, rel, NULL, ops, 0) < 0)
     908           0 :                 msg = createException(SQL, "RAstatement2", "%s", m->errstr);
     909         184 :         rel_destroy(rel);
     910         184 :         return RAstatement2_return(be, m, nlevels, gvars, gentries, msg);
     911             : }
     912             : 
     913             : str
     914         184 : RAstatementEnd(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     915             : {
     916         184 :         backend *be = NULL;
     917         184 :         mvc *m = NULL;
     918         184 :         str msg = MAL_SUCCEED;
     919             : 
     920         184 :         (void) stk;
     921         184 :         (void) pci;
     922         184 :         if ((msg = getSQLContext(cntxt, mb, &m, &be)) != NULL)
     923             :                 return msg;
     924         184 :         if ((msg = checkSQLContext(cntxt)) != NULL)
     925             :                 return msg;
     926             : 
     927         184 :         sqlcleanup(be, 0);
     928         184 :         return SQLautocommit(m);
     929             : }

Generated by: LCOV version 1.14