LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_execute.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 382 520 73.5 %
Date: 2021-10-13 02:24:04 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.14