LCOV - code coverage report
Current view: top level - sql/server - sql_scan.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 838 878 95.4 %
Date: 2021-10-13 02:24:04 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include <wctype.h>
      11             : #include "sql_mem.h"
      12             : #include "sql_scan.h"
      13             : #include "sql_types.h"
      14             : #include "sql_symbol.h"
      15             : #include "sql_mvc.h"
      16             : #include "sql_parser.tab.h"
      17             : #include "sql_semantic.h"
      18             : #include "sql_parser.h"               /* for sql_error() */
      19             : 
      20             : #include "stream.h"
      21             : #include "mapi_prompt.h"
      22             : #include <unistd.h>
      23             : #include <string.h>
      24             : #include <ctype.h>
      25             : #include "sql_keyword.h"
      26             : 
      27             : /**
      28             :  * Removes all comments before the query. In query comments are kept.
      29             :  */
      30             : char *
      31      229698 : query_cleaned(sql_allocator *sa, const char *query)
      32             : {
      33             :         char *q, *r, *c = NULL;
      34             :         int lines = 0;
      35             :         int quote = 0;          /* inside quotes ('..', "..", {..}) */
      36             :         bool bs = false;                /* seen a backslash in a quoted string */
      37             :         bool incomment1 = false;        /* inside traditional C style comment */
      38             :         bool incomment2 = false;        /* inside comment starting with --  */
      39             :         bool inline_comment = false;
      40             : 
      41      229698 :         r = SA_NEW_ARRAY(sa, char, strlen(query) + 1);
      42      229698 :         if(!r)
      43             :                 return NULL;
      44             : 
      45    49748463 :         for (q = r; *query; query++) {
      46    49518765 :                 if (incomment1) {
      47       13358 :                         if (*query == '/' && query[-1] == '*') {
      48             :                                 incomment1 = false;
      49         190 :                                 if (c == r && lines > 0) {
      50             :                                         q = r; // reset to beginning
      51             :                                         lines = 0;
      52         186 :                                         continue;
      53             :                                 }
      54             :                         }
      55       13172 :                         if (*query == '\n') lines++;
      56       13172 :                         *q++ = *query;
      57    49505407 :                 } else if (incomment2) {
      58      854851 :                         if (*query == '\n') {
      59             :                                 incomment2 = false;
      60             :                                 inline_comment = false;
      61             :                                 /* add newline only if comment doesn't
      62             :                                  * occupy whole line */
      63        3585 :                                 if (q > r && q[-1] != '\n'){
      64        1068 :                                         *q++ = '\n';
      65        1068 :                                         lines++;
      66             :                                 }
      67      851266 :                         } else if (inline_comment){
      68       25202 :                                 *q++ = *query; // preserve in line query comments
      69             :                         }
      70    48650556 :                 } else if (quote) {
      71    16494112 :                         if (bs) {
      72             :                                 bs = false;
      73    16486208 :                         } else if (*query == '\\') {
      74             :                                 bs = true;
      75    16478304 :                         } else if (*query == quote) {
      76             :                                 quote = 0;
      77             :                         }
      78    16494112 :                         *q++ = *query;
      79    32156444 :                 } else if (*query == '"' || *query == '\'') {
      80      418311 :                         quote = *query;
      81      418311 :                         *q++ = *query;
      82    31738133 :                 } else if (*query == '{') {
      83             :                         quote = '}';
      84         238 :                         *q++ = *query;
      85    31737895 :                 } else if (*query == '-' && query[1] == '-') {
      86        3585 :                         if (q > r && q[-1] != '\n') {
      87             :                                 inline_comment = true;
      88        1068 :                                 *q++ = *query; // preserve in line query comments
      89             :                         }
      90             :                         incomment2 = true;
      91    31734310 :                 } else if (*query == '/' && query[1] == '*') {
      92             :                         incomment1 = true;
      93             :                         c = q;
      94         190 :                         *q++ = *query;
      95    31734120 :                 } else if (*query == '\n') {
      96             :                         /* collapse newlines */
      97      584003 :                         if (q > r && q[-1] != '\n') {
      98      583464 :                                 *q++ = '\n';
      99      583464 :                                 lines++;
     100             :                         }
     101    31150117 :                 } else if (*query == ' ' || *query == '\t') {
     102             :                         /* collapse white space */
     103     4955624 :                         if (q > r && q[-1] != ' ')
     104     3984767 :                                 *q++ = ' ';
     105             :                 } else {
     106    26194493 :                         *q++ = *query;
     107             :                 }
     108             :         }
     109      229698 :         *q = 0;
     110      229698 :         return r;
     111             : }
     112             : 
     113             : int
     114         266 : scanner_init_keywords(void)
     115             : {
     116             :         int failed = 0;
     117             : 
     118         266 :         failed += keywords_insert("false", BOOL_FALSE);
     119         266 :         failed += keywords_insert("true", BOOL_TRUE);
     120             : 
     121         266 :         failed += keywords_insert("ALTER", ALTER);
     122         266 :         failed += keywords_insert("ADD", ADD);
     123         266 :         failed += keywords_insert("AND", AND);
     124             : 
     125         266 :         failed += keywords_insert("RANK", RANK);
     126         266 :         failed += keywords_insert("DENSE_RANK", RANK);
     127         266 :         failed += keywords_insert("PERCENT_RANK", RANK);
     128         266 :         failed += keywords_insert("CUME_DIST", RANK);
     129         266 :         failed += keywords_insert("ROW_NUMBER", RANK);
     130         266 :         failed += keywords_insert("NTILE", RANK);
     131         266 :         failed += keywords_insert("LAG", RANK);
     132         266 :         failed += keywords_insert("LEAD", RANK);
     133         266 :         failed += keywords_insert("FIRST_VALUE", RANK);
     134         266 :         failed += keywords_insert("LAST_VALUE", RANK);
     135         266 :         failed += keywords_insert("NTH_VALUE", RANK);
     136             : 
     137         266 :         failed += keywords_insert("BEST", BEST);
     138         266 :         failed += keywords_insert("EFFORT", EFFORT);
     139             : 
     140         266 :         failed += keywords_insert("AS", AS);
     141         266 :         failed += keywords_insert("ASC", ASC);
     142         266 :         failed += keywords_insert("AUTHORIZATION", AUTHORIZATION);
     143         266 :         failed += keywords_insert("BETWEEN", BETWEEN);
     144         266 :         failed += keywords_insert("SYMMETRIC", SYMMETRIC);
     145         266 :         failed += keywords_insert("ASYMMETRIC", ASYMMETRIC);
     146         266 :         failed += keywords_insert("BY", BY);
     147         266 :         failed += keywords_insert("CAST", CAST);
     148         266 :         failed += keywords_insert("CONVERT", CONVERT);
     149         266 :         failed += keywords_insert("CHARACTER", CHARACTER);
     150         266 :         failed += keywords_insert("CHAR", CHARACTER);
     151         266 :         failed += keywords_insert("VARYING", VARYING);
     152         266 :         failed += keywords_insert("VARCHAR", VARCHAR);
     153         266 :         failed += keywords_insert("BINARY", BINARY);
     154         266 :         failed += keywords_insert("LARGE", LARGE);
     155         266 :         failed += keywords_insert("OBJECT", OBJECT);
     156         266 :         failed += keywords_insert("CLOB", CLOB);
     157         266 :         failed += keywords_insert("BLOB", sqlBLOB);
     158         266 :         failed += keywords_insert("TEXT", sqlTEXT);
     159         266 :         failed += keywords_insert("TINYTEXT", sqlTEXT);
     160         266 :         failed += keywords_insert("STRING", CLOB);    /* ? */
     161         266 :         failed += keywords_insert("CHECK", CHECK);
     162         266 :         failed += keywords_insert("CLIENT", CLIENT);
     163         266 :         failed += keywords_insert("SERVER", SERVER);
     164         266 :         failed += keywords_insert("COMMENT", COMMENT);
     165         266 :         failed += keywords_insert("CONSTRAINT", CONSTRAINT);
     166         266 :         failed += keywords_insert("CREATE", CREATE);
     167         266 :         failed += keywords_insert("CROSS", CROSS);
     168         266 :         failed += keywords_insert("COPY", COPY);
     169         266 :         failed += keywords_insert("RECORDS", RECORDS);
     170         266 :         failed += keywords_insert("DELIMITERS", DELIMITERS);
     171         266 :         failed += keywords_insert("STDIN", STDIN);
     172         266 :         failed += keywords_insert("STDOUT", STDOUT);
     173             : 
     174         266 :         failed += keywords_insert("TINYINT", TINYINT);
     175         266 :         failed += keywords_insert("SMALLINT", SMALLINT);
     176         266 :         failed += keywords_insert("INTEGER", sqlINTEGER);
     177         266 :         failed += keywords_insert("INT", sqlINTEGER);
     178         266 :         failed += keywords_insert("MEDIUMINT", sqlINTEGER);
     179         266 :         failed += keywords_insert("BIGINT", BIGINT);
     180             : #ifdef HAVE_HGE
     181         266 :         failed += keywords_insert("HUGEINT", HUGEINT);
     182             : #endif
     183         266 :         failed += keywords_insert("DEC", sqlDECIMAL);
     184         266 :         failed += keywords_insert("DECIMAL", sqlDECIMAL);
     185         266 :         failed += keywords_insert("NUMERIC", sqlDECIMAL);
     186         266 :         failed += keywords_insert("DECLARE", DECLARE);
     187         266 :         failed += keywords_insert("DEFAULT", DEFAULT);
     188         266 :         failed += keywords_insert("DESC", DESC);
     189         266 :         failed += keywords_insert("DISTINCT", DISTINCT);
     190         266 :         failed += keywords_insert("DOUBLE", sqlDOUBLE);
     191         266 :         failed += keywords_insert("REAL", sqlREAL);
     192         266 :         failed += keywords_insert("DROP", DROP);
     193         266 :         failed += keywords_insert("ESCAPE", ESCAPE);
     194         266 :         failed += keywords_insert("EXISTS", EXISTS);
     195         266 :         failed += keywords_insert("UESCAPE", UESCAPE);
     196         266 :         failed += keywords_insert("EXTRACT", EXTRACT);
     197         266 :         failed += keywords_insert("FLOAT", sqlFLOAT);
     198         266 :         failed += keywords_insert("FOR", FOR);
     199         266 :         failed += keywords_insert("FOREIGN", FOREIGN);
     200         266 :         failed += keywords_insert("FROM", FROM);
     201         266 :         failed += keywords_insert("FWF", FWF);
     202             : 
     203         266 :         failed += keywords_insert("BIG", BIG);
     204         266 :         failed += keywords_insert("LITTLE", LITTLE);
     205         266 :         failed += keywords_insert("NATIVE", NATIVE);
     206         266 :         failed += keywords_insert("ENDIAN", ENDIAN);
     207             : 
     208         266 :         failed += keywords_insert("REFERENCES", REFERENCES);
     209             : 
     210         266 :         failed += keywords_insert("MATCH", MATCH);
     211         266 :         failed += keywords_insert("FULL", FULL);
     212         266 :         failed += keywords_insert("PARTIAL", PARTIAL);
     213         266 :         failed += keywords_insert("SIMPLE", SIMPLE);
     214             : 
     215         266 :         failed += keywords_insert("INSERT", INSERT);
     216         266 :         failed += keywords_insert("UPDATE", UPDATE);
     217         266 :         failed += keywords_insert("DELETE", sqlDELETE);
     218         266 :         failed += keywords_insert("TRUNCATE", TRUNCATE);
     219         266 :         failed += keywords_insert("MATCHED", MATCHED);
     220             : 
     221         266 :         failed += keywords_insert("ACTION", ACTION);
     222         266 :         failed += keywords_insert("CASCADE", CASCADE);
     223         266 :         failed += keywords_insert("RESTRICT", RESTRICT);
     224         266 :         failed += keywords_insert("FIRST", FIRST);
     225         266 :         failed += keywords_insert("GLOBAL", GLOBAL);
     226         266 :         failed += keywords_insert("GROUP", sqlGROUP);
     227         266 :         failed += keywords_insert("GROUPING", GROUPING);
     228         266 :         failed += keywords_insert("ROLLUP", ROLLUP);
     229         266 :         failed += keywords_insert("CUBE", CUBE);
     230         266 :         failed += keywords_insert("HAVING", HAVING);
     231         266 :         failed += keywords_insert("ILIKE", ILIKE);
     232         266 :         failed += keywords_insert("IMPRINTS", IMPRINTS);
     233         266 :         failed += keywords_insert("IN", sqlIN);
     234         266 :         failed += keywords_insert("INNER", INNER);
     235         266 :         failed += keywords_insert("INTO", INTO);
     236         266 :         failed += keywords_insert("IS", IS);
     237         266 :         failed += keywords_insert("JOIN", JOIN);
     238         266 :         failed += keywords_insert("KEY", KEY);
     239         266 :         failed += keywords_insert("LATERAL", LATERAL);
     240         266 :         failed += keywords_insert("LEFT", LEFT);
     241         266 :         failed += keywords_insert("LIKE", LIKE);
     242         266 :         failed += keywords_insert("LIMIT", LIMIT);
     243         266 :         failed += keywords_insert("SAMPLE", SAMPLE);
     244         266 :         failed += keywords_insert("SEED", SEED);
     245         266 :         failed += keywords_insert("LAST", LAST);
     246         266 :         failed += keywords_insert("LOCAL", LOCAL);
     247         266 :         failed += keywords_insert("NATURAL", NATURAL);
     248         266 :         failed += keywords_insert("NOT", NOT);
     249         266 :         failed += keywords_insert("NULL", sqlNULL);
     250         266 :         failed += keywords_insert("NULLS", NULLS);
     251         266 :         failed += keywords_insert("OFFSET", OFFSET);
     252         266 :         failed += keywords_insert("ON", ON);
     253         266 :         failed += keywords_insert("OPTIONS", OPTIONS);
     254         266 :         failed += keywords_insert("OPTION", OPTION);
     255         266 :         failed += keywords_insert("OR", OR);
     256         266 :         failed += keywords_insert("ORDER", ORDER);
     257         266 :         failed += keywords_insert("ORDERED", ORDERED);
     258         266 :         failed += keywords_insert("OUTER", OUTER);
     259         266 :         failed += keywords_insert("OVER", OVER);
     260         266 :         failed += keywords_insert("PARTITION", PARTITION);
     261         266 :         failed += keywords_insert("PATH", PATH);
     262         266 :         failed += keywords_insert("PRECISION", PRECISION);
     263         266 :         failed += keywords_insert("PRIMARY", PRIMARY);
     264             : 
     265         266 :         failed += keywords_insert("USER", USER);
     266         266 :         failed += keywords_insert("RENAME", RENAME);
     267         266 :         failed += keywords_insert("UNENCRYPTED", UNENCRYPTED);
     268         266 :         failed += keywords_insert("ENCRYPTED", ENCRYPTED);
     269         266 :         failed += keywords_insert("PASSWORD", PASSWORD);
     270         266 :         failed += keywords_insert("GRANT", GRANT);
     271         266 :         failed += keywords_insert("REVOKE", REVOKE);
     272         266 :         failed += keywords_insert("ROLE", ROLE);
     273         266 :         failed += keywords_insert("ADMIN", ADMIN);
     274         266 :         failed += keywords_insert("PRIVILEGES", PRIVILEGES);
     275         266 :         failed += keywords_insert("PUBLIC", PUBLIC);
     276         266 :         failed += keywords_insert("CURRENT_USER", CURRENT_USER);
     277         266 :         failed += keywords_insert("CURRENT_ROLE", CURRENT_ROLE);
     278         266 :         failed += keywords_insert("SESSION_USER", SESSION_USER);
     279         266 :         failed += keywords_insert("CURRENT_SCHEMA", CURRENT_SCHEMA);
     280         266 :         failed += keywords_insert("SESSION", sqlSESSION);
     281             : 
     282         266 :         failed += keywords_insert("RIGHT", RIGHT);
     283         266 :         failed += keywords_insert("SCHEMA", SCHEMA);
     284         266 :         failed += keywords_insert("SELECT", SELECT);
     285         266 :         failed += keywords_insert("SET", SET);
     286         266 :         failed += keywords_insert("SETS", SETS);
     287         266 :         failed += keywords_insert("AUTO_COMMIT", AUTO_COMMIT);
     288             : 
     289         266 :         failed += keywords_insert("ALL", ALL);
     290         266 :         failed += keywords_insert("ANY", ANY);
     291         266 :         failed += keywords_insert("SOME", SOME);
     292         266 :         failed += keywords_insert("EVERY", ANY);
     293             :         /*
     294             :            failed += keywords_insert("SQLCODE", SQLCODE );
     295             :          */
     296         266 :         failed += keywords_insert("COLUMN", COLUMN);
     297         266 :         failed += keywords_insert("TABLE", TABLE);
     298         266 :         failed += keywords_insert("TEMPORARY", TEMPORARY);
     299         266 :         failed += keywords_insert("TEMP", TEMP);
     300         266 :         failed += keywords_insert("REMOTE", REMOTE);
     301         266 :         failed += keywords_insert("MERGE", MERGE);
     302         266 :         failed += keywords_insert("REPLICA", REPLICA);
     303         266 :         failed += keywords_insert("TO", TO);
     304         266 :         failed += keywords_insert("UNION", UNION);
     305         266 :         failed += keywords_insert("EXCEPT", EXCEPT);
     306         266 :         failed += keywords_insert("INTERSECT", INTERSECT);
     307         266 :         failed += keywords_insert("CORRESPONDING", CORRESPONDING);
     308         266 :         failed += keywords_insert("UNIQUE", UNIQUE);
     309         266 :         failed += keywords_insert("USING", USING);
     310         266 :         failed += keywords_insert("VALUES", VALUES);
     311         266 :         failed += keywords_insert("VIEW", VIEW);
     312         266 :         failed += keywords_insert("WHERE", WHERE);
     313         266 :         failed += keywords_insert("WITH", WITH);
     314         266 :         failed += keywords_insert("DATA", DATA);
     315             : 
     316         266 :         failed += keywords_insert("DATE", sqlDATE);
     317         266 :         failed += keywords_insert("TIME", TIME);
     318         266 :         failed += keywords_insert("TIMESTAMP", TIMESTAMP);
     319         266 :         failed += keywords_insert("INTERVAL", INTERVAL);
     320         266 :         failed += keywords_insert("CURRENT_DATE", CURRENT_DATE);
     321         266 :         failed += keywords_insert("CURRENT_TIME", CURRENT_TIME);
     322         266 :         failed += keywords_insert("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP);
     323         266 :         failed += keywords_insert("CURRENT_TIMEZONE", CURRENT_TIMEZONE);
     324         266 :         failed += keywords_insert("NOW", CURRENT_TIMESTAMP);
     325         266 :         failed += keywords_insert("LOCALTIME", LOCALTIME);
     326         266 :         failed += keywords_insert("LOCALTIMESTAMP", LOCALTIMESTAMP);
     327         266 :         failed += keywords_insert("ZONE", ZONE);
     328             : 
     329         266 :         failed += keywords_insert("CENTURY", CENTURY);
     330         266 :         failed += keywords_insert("DECADE", DECADE);
     331         266 :         failed += keywords_insert("YEAR", YEAR);
     332         266 :         failed += keywords_insert("QUARTER", QUARTER);
     333         266 :         failed += keywords_insert("MONTH", MONTH);
     334         266 :         failed += keywords_insert("WEEK", WEEK);
     335         266 :         failed += keywords_insert("DOW", DOW);
     336         266 :         failed += keywords_insert("DOY", DOY);
     337         266 :         failed += keywords_insert("DAY", DAY);
     338         266 :         failed += keywords_insert("HOUR", HOUR);
     339         266 :         failed += keywords_insert("MINUTE", MINUTE);
     340         266 :         failed += keywords_insert("SECOND", SECOND);
     341         266 :         failed += keywords_insert("EPOCH", EPOCH);
     342             : 
     343         266 :         failed += keywords_insert("POSITION", POSITION);
     344         266 :         failed += keywords_insert("SUBSTRING", SUBSTRING);
     345         266 :         failed += keywords_insert("SPLIT_PART", SPLIT_PART);
     346             : 
     347         266 :         failed += keywords_insert("CASE", CASE);
     348         266 :         failed += keywords_insert("WHEN", WHEN);
     349         266 :         failed += keywords_insert("THEN", THEN);
     350         266 :         failed += keywords_insert("ELSE", ELSE);
     351         266 :         failed += keywords_insert("END", END);
     352         266 :         failed += keywords_insert("NULLIF", NULLIF);
     353         266 :         failed += keywords_insert("COALESCE", COALESCE);
     354         266 :         failed += keywords_insert("ELSEIF", ELSEIF);
     355         266 :         failed += keywords_insert("IF", IF);
     356         266 :         failed += keywords_insert("WHILE", WHILE);
     357         266 :         failed += keywords_insert("DO", DO);
     358             : 
     359         266 :         failed += keywords_insert("COMMIT", COMMIT);
     360         266 :         failed += keywords_insert("ROLLBACK", ROLLBACK);
     361         266 :         failed += keywords_insert("SAVEPOINT", SAVEPOINT);
     362         266 :         failed += keywords_insert("RELEASE", RELEASE);
     363         266 :         failed += keywords_insert("WORK", WORK);
     364         266 :         failed += keywords_insert("CHAIN", CHAIN);
     365         266 :         failed += keywords_insert("PRESERVE", PRESERVE);
     366         266 :         failed += keywords_insert("ROWS", ROWS);
     367         266 :         failed += keywords_insert("NO", NO);
     368         266 :         failed += keywords_insert("START", START);
     369         266 :         failed += keywords_insert("TRANSACTION", TRANSACTION);
     370         266 :         failed += keywords_insert("READ", READ);
     371         266 :         failed += keywords_insert("WRITE", WRITE);
     372         266 :         failed += keywords_insert("ONLY", ONLY);
     373         266 :         failed += keywords_insert("ISOLATION", ISOLATION);
     374         266 :         failed += keywords_insert("LEVEL", LEVEL);
     375         266 :         failed += keywords_insert("UNCOMMITTED", UNCOMMITTED);
     376         266 :         failed += keywords_insert("COMMITTED", COMMITTED);
     377         266 :         failed += keywords_insert("REPEATABLE", sqlREPEATABLE);
     378         266 :         failed += keywords_insert("SNAPSHOT", SNAPSHOT);
     379         266 :         failed += keywords_insert("SERIALIZABLE", SERIALIZABLE);
     380         266 :         failed += keywords_insert("DIAGNOSTICS", DIAGNOSTICS);
     381         266 :         failed += keywords_insert("SIZE", sqlSIZE);
     382         266 :         failed += keywords_insert("STORAGE", STORAGE);
     383             : 
     384         266 :         failed += keywords_insert("TYPE", TYPE);
     385         266 :         failed += keywords_insert("PROCEDURE", PROCEDURE);
     386         266 :         failed += keywords_insert("FUNCTION", FUNCTION);
     387         266 :         failed += keywords_insert("LOADER", sqlLOADER);
     388         266 :         failed += keywords_insert("REPLACE", REPLACE);
     389             : 
     390         266 :         failed += keywords_insert("FILTER", FILTER);
     391         266 :         failed += keywords_insert("AGGREGATE", AGGREGATE);
     392         266 :         failed += keywords_insert("RETURNS", RETURNS);
     393         266 :         failed += keywords_insert("EXTERNAL", EXTERNAL);
     394         266 :         failed += keywords_insert("NAME", sqlNAME);
     395         266 :         failed += keywords_insert("RETURN", RETURN);
     396         266 :         failed += keywords_insert("CALL", CALL);
     397         266 :         failed += keywords_insert("LANGUAGE", LANGUAGE);
     398             : 
     399         266 :         failed += keywords_insert("ANALYZE", ANALYZE);
     400         266 :         failed += keywords_insert("MINMAX", MINMAX);
     401         266 :         failed += keywords_insert("EXPLAIN", SQL_EXPLAIN);
     402         266 :         failed += keywords_insert("PLAN", SQL_PLAN);
     403         266 :         failed += keywords_insert("DEBUG", SQL_DEBUG);
     404         266 :         failed += keywords_insert("TRACE", SQL_TRACE);
     405         266 :         failed += keywords_insert("PREPARE", PREPARE);
     406         266 :         failed += keywords_insert("PREP", PREP);
     407         266 :         failed += keywords_insert("EXECUTE", EXECUTE);
     408         266 :         failed += keywords_insert("EXEC", EXEC);
     409         266 :         failed += keywords_insert("DEALLOCATE", DEALLOCATE);
     410             : 
     411         266 :         failed += keywords_insert("INDEX", INDEX);
     412             : 
     413         266 :         failed += keywords_insert("SEQUENCE", SEQUENCE);
     414         266 :         failed += keywords_insert("RESTART", RESTART);
     415         266 :         failed += keywords_insert("INCREMENT", INCREMENT);
     416         266 :         failed += keywords_insert("MAXVALUE", MAXVALUE);
     417         266 :         failed += keywords_insert("MINVALUE", MINVALUE);
     418         266 :         failed += keywords_insert("CYCLE", CYCLE);
     419         266 :         failed += keywords_insert("CACHE", CACHE);
     420         266 :         failed += keywords_insert("NEXT", NEXT);
     421         266 :         failed += keywords_insert("VALUE", VALUE);
     422         266 :         failed += keywords_insert("GENERATED", GENERATED);
     423         266 :         failed += keywords_insert("ALWAYS", ALWAYS);
     424         266 :         failed += keywords_insert("IDENTITY", IDENTITY);
     425         266 :         failed += keywords_insert("SERIAL", SERIAL);
     426         266 :         failed += keywords_insert("BIGSERIAL", BIGSERIAL);
     427         266 :         failed += keywords_insert("AUTO_INCREMENT", AUTO_INCREMENT);
     428         266 :         failed += keywords_insert("CONTINUE", CONTINUE);
     429             : 
     430         266 :         failed += keywords_insert("TRIGGER", TRIGGER);
     431         266 :         failed += keywords_insert("ATOMIC", ATOMIC);
     432         266 :         failed += keywords_insert("BEGIN", BEGIN);
     433         266 :         failed += keywords_insert("OF", OF);
     434         266 :         failed += keywords_insert("BEFORE", BEFORE);
     435         266 :         failed += keywords_insert("AFTER", AFTER);
     436         266 :         failed += keywords_insert("ROW", ROW);
     437         266 :         failed += keywords_insert("STATEMENT", STATEMENT);
     438         266 :         failed += keywords_insert("NEW", sqlNEW);
     439         266 :         failed += keywords_insert("OLD", OLD);
     440         266 :         failed += keywords_insert("EACH", EACH);
     441         266 :         failed += keywords_insert("REFERENCING", REFERENCING);
     442             : 
     443         266 :         failed += keywords_insert("RANGE", RANGE);
     444         266 :         failed += keywords_insert("UNBOUNDED", UNBOUNDED);
     445         266 :         failed += keywords_insert("PRECEDING", PRECEDING);
     446         266 :         failed += keywords_insert("FOLLOWING", FOLLOWING);
     447         266 :         failed += keywords_insert("CURRENT", CURRENT);
     448         266 :         failed += keywords_insert("EXCLUDE", EXCLUDE);
     449         266 :         failed += keywords_insert("OTHERS", OTHERS);
     450         266 :         failed += keywords_insert("TIES", TIES);
     451         266 :         failed += keywords_insert("GROUPS", GROUPS);
     452         266 :         failed += keywords_insert("WINDOW", WINDOW);
     453             : 
     454             :         /* special SQL/XML keywords */
     455         266 :         failed += keywords_insert("XMLCOMMENT", XMLCOMMENT);
     456         266 :         failed += keywords_insert("XMLCONCAT", XMLCONCAT);
     457         266 :         failed += keywords_insert("XMLDOCUMENT", XMLDOCUMENT);
     458         266 :         failed += keywords_insert("XMLELEMENT", XMLELEMENT);
     459         266 :         failed += keywords_insert("XMLATTRIBUTES", XMLATTRIBUTES);
     460         266 :         failed += keywords_insert("XMLFOREST", XMLFOREST);
     461         266 :         failed += keywords_insert("XMLPARSE", XMLPARSE);
     462         266 :         failed += keywords_insert("STRIP", STRIP);
     463         266 :         failed += keywords_insert("WHITESPACE", WHITESPACE);
     464         266 :         failed += keywords_insert("XMLPI", XMLPI);
     465         266 :         failed += keywords_insert("XMLQUERY", XMLQUERY);
     466         266 :         failed += keywords_insert("PASSING", PASSING);
     467         266 :         failed += keywords_insert("XMLTEXT", XMLTEXT);
     468         266 :         failed += keywords_insert("NIL", NIL);
     469         266 :         failed += keywords_insert("REF", REF);
     470         266 :         failed += keywords_insert("ABSENT", ABSENT);
     471         266 :         failed += keywords_insert("DOCUMENT", DOCUMENT);
     472         266 :         failed += keywords_insert("ELEMENT", ELEMENT);
     473         266 :         failed += keywords_insert("CONTENT", CONTENT);
     474         266 :         failed += keywords_insert("XMLNAMESPACES", XMLNAMESPACES);
     475         266 :         failed += keywords_insert("NAMESPACE", NAMESPACE);
     476         266 :         failed += keywords_insert("XMLVALIDATE", XMLVALIDATE);
     477         266 :         failed += keywords_insert("RETURNING", RETURNING);
     478         266 :         failed += keywords_insert("LOCATION", LOCATION);
     479         266 :         failed += keywords_insert("ID", ID);
     480         266 :         failed += keywords_insert("ACCORDING", ACCORDING);
     481         266 :         failed += keywords_insert("XMLSCHEMA", XMLSCHEMA);
     482         266 :         failed += keywords_insert("URI", URI);
     483         266 :         failed += keywords_insert("XMLAGG", XMLAGG);
     484             : 
     485             :         /* keywords for opengis */
     486         266 :         failed += keywords_insert("GEOMETRY", GEOMETRY);
     487             : 
     488         266 :         failed += keywords_insert("POINT", GEOMETRYSUBTYPE);
     489         266 :         failed += keywords_insert("LINESTRING", GEOMETRYSUBTYPE);
     490         266 :         failed += keywords_insert("POLYGON", GEOMETRYSUBTYPE);
     491         266 :         failed += keywords_insert("MULTIPOINT", GEOMETRYSUBTYPE);
     492         266 :         failed += keywords_insert("MULTILINESTRING", GEOMETRYSUBTYPE);
     493         266 :         failed += keywords_insert("MULTIPOLYGON", GEOMETRYSUBTYPE);
     494         266 :         failed += keywords_insert("GEOMETRYCOLLECTION", GEOMETRYSUBTYPE);
     495             : 
     496         266 :         failed += keywords_insert("POINTZ", GEOMETRYSUBTYPE);
     497         266 :         failed += keywords_insert("LINESTRINGZ", GEOMETRYSUBTYPE);
     498         266 :         failed += keywords_insert("POLYGONZ", GEOMETRYSUBTYPE);
     499         266 :         failed += keywords_insert("MULTIPOINTZ", GEOMETRYSUBTYPE);
     500         266 :         failed += keywords_insert("MULTILINESTRINGZ", GEOMETRYSUBTYPE);
     501         266 :         failed += keywords_insert("MULTIPOLYGONZ", GEOMETRYSUBTYPE);
     502         266 :         failed += keywords_insert("GEOMETRYCOLLECTIONZ", GEOMETRYSUBTYPE);
     503             : 
     504         266 :         failed += keywords_insert("POINTM", GEOMETRYSUBTYPE);
     505         266 :         failed += keywords_insert("LINESTRINGM", GEOMETRYSUBTYPE);
     506         266 :         failed += keywords_insert("POLYGONM", GEOMETRYSUBTYPE);
     507         266 :         failed += keywords_insert("MULTIPOINTM", GEOMETRYSUBTYPE);
     508         266 :         failed += keywords_insert("MULTILINESTRINGM", GEOMETRYSUBTYPE);
     509         266 :         failed += keywords_insert("MULTIPOLYGONM", GEOMETRYSUBTYPE);
     510         266 :         failed += keywords_insert("GEOMETRYCOLLECTIONM", GEOMETRYSUBTYPE);
     511             : 
     512         266 :         failed += keywords_insert("POINTZM", GEOMETRYSUBTYPE);
     513         266 :         failed += keywords_insert("LINESTRINGZM", GEOMETRYSUBTYPE);
     514         266 :         failed += keywords_insert("POLYGONZM", GEOMETRYSUBTYPE);
     515         266 :         failed += keywords_insert("MULTIPOINTZM", GEOMETRYSUBTYPE);
     516         266 :         failed += keywords_insert("MULTILINESTRINGZM", GEOMETRYSUBTYPE);
     517         266 :         failed += keywords_insert("MULTIPOLYGONZM", GEOMETRYSUBTYPE);
     518         266 :         failed += keywords_insert("GEOMETRYCOLLECTIONZM", GEOMETRYSUBTYPE);
     519             : 
     520         266 :         return failed;
     521             : }
     522             : 
     523             : #define find_keyword_bs(lc, s) find_keyword(lc->rs->buf+lc->rs->pos+s)
     524             : 
     525             : void
     526      167532 : scanner_init(struct scanner *s, bstream *rs, stream *ws)
     527             : {
     528      167532 :         *s = (struct scanner) {
     529             :                 .rs = rs,
     530             :                 .ws = ws,
     531             :                 .mode = LINE_N,
     532      167532 :                 .raw_string_mode = GDKgetenv_istrue("raw_strings"),
     533             :         };
     534      167532 : }
     535             : 
     536             : void
     537      806522 : scanner_query_processed(struct scanner *s)
     538             : {
     539             :         int cur;
     540             : 
     541      806522 :         if (s->yybak) {
     542      303620 :                 s->rs->buf[s->rs->pos + s->yycur] = s->yybak;
     543      303620 :                 s->yybak = 0;
     544             :         }
     545      806522 :         if (s->rs) {
     546      806522 :                 s->rs->pos += s->yycur;
     547             :                 /* completely eat the query including white space after the ; */
     548     1129744 :                 while (s->rs->pos < s->rs->len &&
     549      872708 :                            (cur = s->rs->buf[s->rs->pos], iswspace(cur))) {
     550      323222 :                         s->rs->pos++;
     551             :                 }
     552             :         }
     553             :         /*assert(s->rs->pos <= s->rs->len);*/
     554      806522 :         s->yycur = 0;
     555      806522 :         s->started = 0;
     556      806522 :         s->as = 0;
     557      806522 :         s->schema = NULL;
     558      806522 : }
     559             : 
     560             : static int
     561          33 : scanner_error(mvc *lc, int cur)
     562             : {
     563          33 :         switch (cur) {
     564           0 :         case EOF:
     565           0 :                 (void) sql_error(lc, 1, SQLSTATE(42000) "Unexpected end of input");
     566           0 :                 return -1;      /* EOF needs -1 result */
     567          33 :         default:
     568             :                 /* on Windows at least, iswcntrl returns TRUE for
     569             :                  * U+FEFF, but we just want consistent error
     570             :                  * messages */
     571          43 :                 (void) sql_error(lc, 1, SQLSTATE(42000) "Unexpected%s character (U+%04X)", iswcntrl(cur) && cur != 0xFEFF ? " control" : "", (unsigned) cur);
     572             :         }
     573          33 :         return LEX_ERROR;
     574             : }
     575             : 
     576             : 
     577             : /*
     578             :    UTF-8 encoding is as follows:
     579             : U-00000000 - U-0000007F: 0xxxxxxx
     580             : U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
     581             : U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
     582             : U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
     583             : U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     584             : U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     585             : */
     586             : /* To be correctly coded UTF-8, the sequence should be the shortest
     587             :    possible encoding of the value being encoded.  This means that for
     588             :    an encoding of length n+1 (1 <= n <= 5), at least one of the bits in
     589             :    utf8chkmsk[n] should be non-zero (else the encoding could be
     590             :    shorter).
     591             : */
     592             : static int utf8chkmsk[] = {
     593             :         0x0000007f,
     594             :         0x00000780,
     595             :         0x0000f800,
     596             :         0x001f0000,
     597             :         0x03e00000,
     598             :         0x7c000000
     599             : };
     600             : 
     601             : static void
     602    23457168 : utf8_putchar(struct scanner *lc, int ch)
     603             : {
     604    23457168 :         if ((ch) < 0x80) {
     605    23457163 :                 lc->yycur--;
     606           5 :         } else if ((ch) < 0x800) {
     607           0 :                 lc->yycur -= 2;
     608           5 :         } else if ((ch) < 0x10000) {
     609           5 :                 lc->yycur -= 3;
     610             :         } else {
     611           0 :                 lc->yycur -= 4;
     612             :         }
     613    23457168 : }
     614             : 
     615             : static inline int
     616    99872933 : scanner_read_more(struct scanner *lc, size_t n)
     617             : {
     618    99872933 :         bstream *b = lc->rs;
     619             :         bool more = false;
     620             : 
     621             : 
     622    99876812 :         while (b->len < b->pos + lc->yycur + n) {
     623             : 
     624       30812 :                 if (lc->mode == LINE_1 || !lc->started)
     625             :                         return EOF;
     626             : 
     627             :                 /* query is not finished ask for more */
     628        3884 :                 if (b->eof || !isa_block_stream(b->s)) {
     629        1943 :                         if (mnstr_write(lc->ws, PROMPT2, sizeof(PROMPT2) - 1, 1) == 1)
     630        1943 :                                 mnstr_flush(lc->ws, MNSTR_FLUSH_DATA);
     631        1943 :                         b->eof = false;
     632             :                         more = true;
     633             :                 }
     634             :                 /* we need more query text */
     635        3884 :                 if (bstream_next(b) < 0 ||
     636             :                     /* we asked for more data but didn't get any */
     637        1943 :                     (more && b->eof && b->len < b->pos + lc->yycur + n))
     638             :                         return EOF;
     639             :         }
     640             :         return 1;
     641             : }
     642             : 
     643             : static inline int
     644    98882262 : scanner_getc(struct scanner *lc)
     645             : {
     646    98882262 :         bstream *b = lc->rs;
     647             :         unsigned char *s = NULL;
     648             :         int c, m, n, mask;
     649             : 
     650    98882262 :         if (scanner_read_more(lc, 1) == EOF) {
     651             :                 //lc->errstr = SQLSTATE(42000) "end of input stream";
     652             :                 return EOF;
     653             :         }
     654    98855343 :         lc->errstr = NULL;
     655             : 
     656    98855343 :         s = (unsigned char *) b->buf + b->pos + lc->yycur++;
     657    98855343 :         if (((c = *s) & 0x80) == 0) {
     658             :                 /* 7-bit char */
     659             :                 return c;
     660             :         }
     661       87585 :         for (n = 0, m = 0x40; c & m; n++, m >>= 1)
     662             :                 ;
     663             :         /* n now is number of 10xxxxxx bytes that should follow */
     664       29170 :         if (n == 0 || n >= 6 || (b->pos + n) > b->len) {
     665             :                 /* incorrect UTF-8 sequence */
     666             :                 /* n==0: c == 10xxxxxx */
     667             :                 /* n>=6: c == 1111111x */
     668           3 :                 lc->errstr = SQLSTATE(42000) "invalid start of UTF-8 sequence";
     669           3 :                 goto error;
     670             :         }
     671             : 
     672       29167 :         if (scanner_read_more(lc, (size_t) n) == EOF)
     673             :                 return EOF;
     674       29167 :         s = (unsigned char *) b->buf + b->pos + lc->yycur;
     675             : 
     676       29167 :         mask = utf8chkmsk[n];
     677       29167 :         c &= ~(0xFFC0 >> n);  /* remove non-x bits */
     678       87581 :         while (--n >= 0) {
     679       58415 :                 c <<= 6;
     680       58415 :                 lc->yycur++;
     681       58415 :                 if (((m = *s++) & 0xC0) != 0x80) {
     682             :                         /* incorrect UTF-8 sequence: byte is not 10xxxxxx */
     683             :                         /* this includes end-of-string (m == 0) */
     684           1 :                         lc->errstr = SQLSTATE(42000) "invalid continuation in UTF-8 sequence";
     685           1 :                         goto error;
     686             :                 }
     687       58414 :                 c |= m & 0x3F;
     688             :         }
     689       29166 :         if ((c & mask) == 0) {
     690             :                 /* incorrect UTF-8 sequence: not shortest possible */
     691           0 :                 lc->errstr = SQLSTATE(42000) "not shortest possible UTF-8 sequence";
     692           0 :                 goto error;
     693             :         }
     694             : 
     695             :         return c;
     696             : 
     697           4 : error:
     698           4 :         if (b->pos + lc->yycur < b->len)    /* skip bogus char */
     699           3 :                 lc->yycur++;
     700             :         return EOF;
     701             : }
     702             : 
     703             : static int
     704             : scanner_token(struct scanner *lc, int token)
     705             : {
     706    20233224 :         lc->yybak = lc->rs->buf[lc->rs->pos + lc->yycur];
     707    20233224 :         lc->rs->buf[lc->rs->pos + lc->yycur] = 0;
     708    20233224 :         lc->yyval = token;
     709             :         return lc->yyval;
     710             : }
     711             : 
     712             : static int
     713     1555713 : scanner_string(mvc *c, int quote, bool escapes)
     714             : {
     715     1555713 :         struct scanner *lc = &c->scanner;
     716     1555713 :         bstream *rs = lc->rs;
     717             :         int cur = quote;
     718             :         bool escape = false;
     719     1555713 :         const size_t limit = quote == '"' ? 1 << 11 : 1 << 30;
     720             : 
     721     1555713 :         lc->started = 1;
     722     1588902 :         while (cur != EOF) {
     723             :                 size_t pos = 0;
     724     1588887 :                 const size_t yycur = rs->pos + lc->yycur;
     725             : 
     726    25142357 :                 while (cur != EOF && (quote != '"' || cur != 0xFEFF) && pos < limit &&
     727    25142356 :                        (((cur = rs->buf[yycur + pos++]) & 0x80) == 0) &&
     728    25113177 :                        cur && (cur != quote || escape)) {
     729    23553470 :                         if (escapes && cur == '\\')
     730       14772 :                                 escape = !escape;
     731             :                         else
     732             :                                 escape = false;
     733             :                 }
     734     1588887 :                 if (pos == limit) {
     735           0 :                         (void) sql_error(c, 2, SQLSTATE(42000) "string too long");
     736           0 :                         return LEX_ERROR;
     737             :                 }
     738             :                 /* BOM character not allowed as an identifier */
     739     1588887 :                 if (cur == EOF || (quote == '"' && cur == 0xFEFF))
     740           1 :                         return scanner_error(c, cur);
     741     1588886 :                 lc->yycur += pos;
     742             :                 /* check for quote escaped quote: Obscure SQL Rule */
     743     1588886 :                 if (cur == quote && rs->buf[yycur + pos] == quote) {
     744        4024 :                         if (escapes)
     745        3923 :                                 rs->buf[yycur + pos - 1] = '\\';
     746        4024 :                         lc->yycur++;
     747        4024 :                         continue;
     748             :                 }
     749     1584862 :                 assert(yycur + pos <= rs->len + 1);
     750     1584862 :                 if (cur == quote && !escape) {
     751     1555683 :                         return scanner_token(lc, STRING);
     752             :                 }
     753       29179 :                 lc->yycur--; /* go back to current (possibly invalid) char */
     754             :                 /* long utf8, if correct isn't the quote */
     755       29179 :                 if (!cur) {
     756          29 :                         if (lc->rs->len >= lc->rs->pos + lc->yycur + 1) {
     757          14 :                                 (void) sql_error(c, 2, SQLSTATE(42000) "NULL byte in string");
     758          14 :                                 return LEX_ERROR;
     759             :                         }
     760          15 :                         cur = scanner_read_more(lc, 1);
     761             :                 } else {
     762       29150 :                         cur = scanner_getc(lc);
     763             :                 }
     764             :         }
     765          16 :         (void) sql_error(c, 2, "%s", lc->errstr ? lc->errstr : SQLSTATE(42000) "unexpected end of input");
     766          15 :         return LEX_ERROR;
     767             : }
     768             : 
     769             : /* scan a structure {blah} into a string. We only count the matching {}
     770             :  * unless escaped. We do not consider embeddings in string literals yet
     771             :  */
     772             : 
     773             : static int
     774         205 : scanner_body(mvc *c)
     775             : {
     776         205 :         struct scanner *lc = &c->scanner;
     777         205 :         bstream *rs = lc->rs;
     778             :         int cur = (int) 'x';
     779             :         int blk = 1;
     780             :         bool escape = false;
     781             : 
     782         205 :         lc->started = 1;
     783         205 :         assert(rs->buf[rs->pos + lc->yycur-1] == '{');
     784         233 :         while (cur != EOF) {
     785         233 :                 size_t pos = rs->pos + lc->yycur;
     786             : 
     787       26870 :                 while ((((cur = rs->buf[pos++]) & 0x80) == 0) && cur && (blk || escape)) {
     788       26637 :                         if (cur != '\\')
     789             :                                 escape = false;
     790             :                         else
     791           8 :                                 escape = !escape;
     792       26637 :                         blk += cur =='{';
     793       26637 :                         blk -= cur =='}';
     794             :                 }
     795         233 :                 lc->yycur = pos - rs->pos;
     796         233 :                 assert(pos <= rs->len + 1);
     797         233 :                 if (blk == 0 && !escape){
     798         205 :                         lc->yycur--; /* go back to current (possibly invalid) char */
     799         205 :                         return scanner_token(lc, X_BODY);
     800             :                 }
     801          28 :                 lc->yycur--; /* go back to current (possibly invalid) char */
     802          28 :                 if (!cur) {
     803          28 :                         if (lc->rs->len >= lc->rs->pos + lc->yycur + 1) {
     804           0 :                                 (void) sql_error(c, 2, SQLSTATE(42000) "NULL byte in string");
     805           0 :                                 return LEX_ERROR;
     806             :                         }
     807          28 :                         cur = scanner_read_more(lc, 1);
     808             :                 } else {
     809           0 :                         cur = scanner_getc(lc);
     810             :                 }
     811             :         }
     812           0 :         (void) sql_error(c, 2, SQLSTATE(42000) "Unexpected end of input");
     813           0 :         return LEX_ERROR;
     814             : }
     815             : 
     816             : static int
     817    10322124 : keyword_or_ident(mvc * c, int cur)
     818             : {
     819    10322124 :         struct scanner *lc = &c->scanner;
     820             :         keyword *k = NULL;
     821             :         size_t s;
     822             : 
     823    10322124 :         lc->started = 1;
     824    10322124 :         utf8_putchar(lc, cur);
     825    10322124 :         s = lc->yycur;
     826    10322124 :         lc->yyval = IDENT;
     827    59752963 :         while ((cur = scanner_getc(lc)) != EOF) {
     828    59752962 :                 if (!iswalnum(cur) && cur != '_') {
     829    10322123 :                         utf8_putchar(lc, cur);
     830             :                         (void)scanner_token(lc, IDENT);
     831    10322123 :                         if ((k = find_keyword_bs(lc,s)))
     832     5857837 :                                 lc->yyval = k->token;
     833    10322123 :                         return lc->yyval;
     834             :                 }
     835             :         }
     836             :         (void)scanner_token(lc, IDENT);
     837           1 :         if ((k = find_keyword_bs(lc,s)))
     838           0 :                 lc->yyval = k->token;
     839           1 :         return lc->yyval;
     840             : }
     841             : 
     842             : static int
     843    10393371 : skip_white_space(struct scanner * lc)
     844             : {
     845             :         int cur;
     846             : 
     847             :         do {
     848    12499048 :                 lc->yysval = lc->yycur;
     849    12499048 :         } while ((cur = scanner_getc(lc)) != EOF && iswspace(cur));
     850    10393371 :         return cur;
     851             : }
     852             : 
     853             : static int
     854       62686 : skip_c_comment(struct scanner * lc)
     855             : {
     856             :         int cur;
     857             :         int prev = 0;
     858       62686 :         int started = lc->started;
     859             :         int depth = 1;
     860             : 
     861       62686 :         lc->started = 1;
     862     1263902 :         while (depth > 0 && (cur = scanner_getc(lc)) != EOF) {
     863     1201216 :                 if (prev == '*' && cur == '/')
     864       62686 :                         depth--;
     865     1138530 :                 else if (prev == '/' && cur == '*') {
     866             :                         /* block comments can nest */
     867             :                         cur = 0; /* prevent slash-star-slash from matching */
     868           0 :                         depth++;
     869             :                 }
     870             :                 prev = cur;
     871             :         }
     872       62686 :         lc->yysval = lc->yycur;
     873       62686 :         lc->started = started;
     874             :         /* a comment is equivalent to a newline */
     875       62686 :         return cur == EOF ? cur : '\n';
     876             : }
     877             : 
     878             : static int
     879        3977 : skip_sql_comment(struct scanner * lc)
     880             : {
     881             :         int cur;
     882        3977 :         int started = lc->started;
     883             : 
     884        3977 :         lc->started = 1;
     885      857764 :         while ((cur = scanner_getc(lc)) != EOF && (cur != '\n'))
     886             :                 ;
     887        3977 :         lc->yysval = lc->yycur;
     888        3977 :         lc->started = started;
     889             :         /* a comment is equivalent to a newline */
     890        3977 :         return cur;
     891             : }
     892             : 
     893             : static int tokenize(mvc * lc, int cur);
     894             : 
     895             : static int
     896      947167 : number(mvc * c, int cur)
     897             : {
     898      947167 :         struct scanner *lc = &c->scanner;
     899             :         int token = sqlINT;
     900             :         int before_cur = EOF;
     901             : 
     902      947167 :         lc->started = 1;
     903      947167 :         if (cur == '0' && (cur = scanner_getc(lc)) == 'x') {
     904        3656 :                 while ((cur = scanner_getc(lc)) != EOF &&
     905        3656 :                        (iswdigit(cur) ||
     906         923 :                                  (cur >= 'A' && cur <= 'F') ||
     907         815 :                                  (cur >= 'a' && cur <= 'f')))
     908             :                         token = HEXADECIMAL;
     909         274 :                 if (token == sqlINT)
     910             :                         before_cur = 'x';
     911             :         } else {
     912      946893 :                 if (iswdigit(cur))
     913     1860686 :                         while ((cur = scanner_getc(lc)) != EOF && iswdigit(cur))
     914             :                                 ;
     915      946893 :                 if (cur == '@') {
     916             :                         token = OIDNUM;
     917           0 :                         cur = scanner_getc(lc);
     918           0 :                         if (cur == '0')
     919           0 :                                 cur = scanner_getc(lc);
     920             :                 }
     921             : 
     922      946893 :                 if (cur == '.') {
     923             :                         token = INTNUM;
     924             : 
     925       46609 :                         while ((cur = scanner_getc(lc)) != EOF && iswdigit(cur))
     926             :                                 ;
     927             :                 }
     928      946893 :                 if (cur == 'e' || cur == 'E') {
     929             :                         token = APPROXNUM;
     930        2227 :                         cur = scanner_getc(lc);
     931        2227 :                         if (cur == '-' || cur == '+')
     932             :                                 token = 0;
     933        6505 :                         while ((cur = scanner_getc(lc)) != EOF && iswdigit(cur))
     934             :                                 token = APPROXNUM;
     935             :                 }
     936             :         }
     937             : 
     938      947167 :         if (cur == EOF && lc->rs->buf == NULL) /* malloc failure */
     939             :                 return EOF;
     940             : 
     941      947167 :         if (token) {
     942      947167 :                 if (cur != EOF)
     943      947167 :                         utf8_putchar(lc, cur);
     944      947167 :                 if (before_cur != EOF)
     945           4 :                         utf8_putchar(lc, before_cur);
     946      947167 :                 return scanner_token(lc, token);
     947             :         } else {
     948           0 :                 (void)sql_error( c, 2, SQLSTATE(42000) "Unexpected symbol %lc", (wint_t) cur);
     949           0 :                 return LEX_ERROR;
     950             :         }
     951             : }
     952             : 
     953             : static
     954     9023982 : int scanner_symbol(mvc * c, int cur)
     955             : {
     956     9023982 :         struct scanner *lc = &c->scanner;
     957             :         int next = 0;
     958     9023982 :         int started = lc->started;
     959             : 
     960     9023982 :         switch (cur) {
     961       65177 :         case '/':
     962       65177 :                 lc->started = 1;
     963       65177 :                 next = scanner_getc(lc);
     964       65177 :                 if (next == '*') {
     965       62686 :                         lc->started = started;
     966       62686 :                         cur = skip_c_comment(lc);
     967       62686 :                         if (cur < 0)
     968             :                                 return EOF;
     969       62686 :                         return tokenize(c, cur);
     970             :                 } else {
     971        2491 :                         utf8_putchar(lc, next);
     972        2491 :                         return scanner_token(lc, cur);
     973             :                 }
     974           0 :         case '0':
     975             :         case '1':
     976             :         case '2':
     977             :         case '3':
     978             :         case '4':
     979             :         case '5':
     980             :         case '6':
     981             :         case '7':
     982             :         case '8':
     983             :         case '9':
     984           0 :                 return number(c, cur);
     985           1 :         case '#':
     986           1 :                 if ((cur = skip_sql_comment(lc)) == EOF)
     987             :                         return cur;
     988           1 :                 return tokenize(c, cur);
     989      631315 :         case '\'':
     990      631315 :                 if (lc->raw_string_mode || lc->next_string_is_raw)
     991          22 :                         return scanner_string(c, cur, false);
     992      631293 :                 return scanner_string(c, cur, true);
     993      917609 :         case '"':
     994      917609 :                 return scanner_string(c, cur, false);
     995         205 :         case '{':
     996         205 :                 return scanner_body(c);
     997       20481 :         case '-':
     998       20481 :                 lc->started = 1;
     999       20481 :                 next = scanner_getc(lc);
    1000       20481 :                 if (next == '-') {
    1001        3976 :                         lc->started = started;
    1002        3976 :                         if ((cur = skip_sql_comment(lc)) == EOF)
    1003             :                                 return cur;
    1004        3976 :                         return tokenize(c, cur);
    1005             :                 }
    1006       16505 :                 lc->started = 1;
    1007       16505 :                 utf8_putchar(lc, next);
    1008       16505 :                 return scanner_token(lc, cur);
    1009          12 :         case '~': /* binary not */
    1010          12 :                 lc->started = 1;
    1011          12 :                 next = scanner_getc(lc);
    1012          12 :                 if (next == '=')
    1013           5 :                         return scanner_token(lc, GEOM_MBR_EQUAL);
    1014           7 :                 utf8_putchar(lc, next);
    1015           7 :                 return scanner_token(lc, cur);
    1016     4712430 :         case '^': /* binary xor */
    1017             :         case '*':
    1018             :         case '?':
    1019             :         case '%':
    1020             :         case '+':
    1021             :         case '(':
    1022             :         case ')':
    1023             :         case ',':
    1024             :         case '=':
    1025             :         case '[':
    1026             :         case ']':
    1027     4712430 :                 lc->started = 1;
    1028     4712430 :                 return scanner_token(lc, cur);
    1029        2795 :         case '&':
    1030        2795 :                 lc->started = 1;
    1031        2795 :                 cur = scanner_getc(lc);
    1032        2795 :                 if(cur == '<') {
    1033           3 :                         next = scanner_getc(lc);
    1034           3 :                         if(next == '|') {
    1035           0 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_BELOW);
    1036             :                         } else {
    1037           3 :                                 utf8_putchar(lc, next); //put the char back
    1038           3 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_LEFT);
    1039             :                         }
    1040        2792 :                 } else if(cur == '>')
    1041           3 :                         return scanner_token(lc, GEOM_OVERLAP_OR_RIGHT);
    1042        2789 :                 else if(cur == '&')
    1043           3 :                         return scanner_token(lc, GEOM_OVERLAP);
    1044             :                 else {/* binary and */
    1045        2786 :                         utf8_putchar(lc, cur); //put the char back
    1046        2786 :                         return scanner_token(lc, '&');
    1047             :                 }
    1048          19 :         case '@':
    1049          19 :                 lc->started = 1;
    1050          19 :                 return scanner_token(lc, AT);
    1051      611483 :         case ';':
    1052      611483 :                 lc->started = 0;
    1053      611483 :                 return scanner_token(lc, SCOLON);
    1054       44544 :         case '<':
    1055       44544 :                 lc->started = 1;
    1056       44544 :                 cur = scanner_getc(lc);
    1057       44544 :                 if (cur == '=') {
    1058        2184 :                         return scanner_token( lc, COMPARISON);
    1059       42360 :                 } else if (cur == '>') {
    1060       32941 :                         return scanner_token( lc, COMPARISON);
    1061        9419 :                 } else if (cur == '<') {
    1062          50 :                         next = scanner_getc(lc);
    1063          50 :                         if (next == '=') {
    1064           4 :                                 return scanner_token( lc, LEFT_SHIFT_ASSIGN);
    1065          46 :                         } else if (next == '|') {
    1066           1 :                                 return scanner_token(lc, GEOM_BELOW);
    1067             :                         } else {
    1068          45 :                                 utf8_putchar(lc, next); //put the char back
    1069          45 :                                 return scanner_token( lc, LEFT_SHIFT);
    1070             :                         }
    1071        9369 :                 } else if(cur == '-') {
    1072          19 :                         next = scanner_getc(lc);
    1073          19 :                         if(next == '>') {
    1074           7 :                                 return scanner_token(lc, GEOM_DIST);
    1075             :                         } else {
    1076             :                                 //put the characters back and fall in the next possible case
    1077          12 :                                 utf8_putchar(lc, next);
    1078          12 :                                 utf8_putchar(lc, cur);
    1079          12 :                                 return scanner_token( lc, COMPARISON);
    1080             :                         }
    1081             :                 } else {
    1082        9350 :                         utf8_putchar(lc, cur);
    1083        9350 :                         return scanner_token( lc, COMPARISON);
    1084             :                 }
    1085       36254 :         case '>':
    1086       36254 :                 lc->started = 1;
    1087       36254 :                 cur = scanner_getc(lc);
    1088       36254 :                 if (cur == '>') {
    1089         900 :                         cur = scanner_getc(lc);
    1090         900 :                         if (cur == '=')
    1091           3 :                                 return scanner_token( lc, RIGHT_SHIFT_ASSIGN);
    1092         897 :                         utf8_putchar(lc, cur);
    1093         897 :                         return scanner_token( lc, RIGHT_SHIFT);
    1094       35354 :                 } else if (cur != '=') {
    1095       33281 :                         utf8_putchar(lc, cur);
    1096       33281 :                         return scanner_token( lc, COMPARISON);
    1097             :                 } else {
    1098        2073 :                         return scanner_token( lc, COMPARISON);
    1099             :                 }
    1100     1800333 :         case '.':
    1101     1800333 :                 lc->started = 1;
    1102     1800333 :                 cur = scanner_getc(lc);
    1103     1800333 :                 if (!iswdigit(cur)) {
    1104     1800320 :                         utf8_putchar(lc, cur);
    1105     1800320 :                         return scanner_token( lc, '.');
    1106             :                 } else {
    1107          13 :                         utf8_putchar(lc, cur);
    1108             :                         cur = '.';
    1109          13 :                         return number(c, cur);
    1110             :                 }
    1111      181192 :         case '|': /* binary or or string concat */
    1112      181192 :                 lc->started = 1;
    1113      181192 :                 cur = scanner_getc(lc);
    1114      181192 :                 if (cur == '|') {
    1115      181163 :                         return scanner_token(lc, CONCATSTRING);
    1116          29 :                 } else if (cur == '&') {
    1117           0 :                         next = scanner_getc(lc);
    1118           0 :                         if(next == '>') {
    1119           0 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_ABOVE);
    1120             :                         } else {
    1121           0 :                                 utf8_putchar(lc, next); //put the char back
    1122           0 :                                 utf8_putchar(lc, cur); //put the char back
    1123           0 :                                 return scanner_token(lc, '|');
    1124             :                         }
    1125          29 :                 } else if (cur == '>') {
    1126           1 :                         next = scanner_getc(lc);
    1127           1 :                         if(next == '>') {
    1128           1 :                                 return scanner_token(lc, GEOM_ABOVE);
    1129             :                         } else {
    1130           0 :                                 utf8_putchar(lc, next); //put the char back
    1131           0 :                                 utf8_putchar(lc, cur); //put the char back
    1132           0 :                                 return scanner_token(lc, '|');
    1133             :                         }
    1134             :                 } else {
    1135          28 :                         utf8_putchar(lc, cur);
    1136          28 :                         return scanner_token(lc, '|');
    1137             :                 }
    1138             :         }
    1139         132 :         (void)sql_error( c, 3, SQLSTATE(42000) "Unexpected symbol (%lc)", (wint_t) cur);
    1140         132 :         return LEX_ERROR;
    1141             : }
    1142             : 
    1143             : static int
    1144    20321508 : tokenize(mvc * c, int cur)
    1145             : {
    1146    20321508 :         struct scanner *lc = &c->scanner;
    1147             :         while (1) {
    1148    30693452 :                 if (cur == 0xFEFF) {
    1149             :                         /* on Linux at least, iswpunct returns TRUE
    1150             :                          * for U+FEFF, but we don't want that, we just
    1151             :                          * want to go to the scanner_error case
    1152             :                          * below */
    1153             :                         ;
    1154    30693443 :                 } else if (iswspace(cur)) {
    1155    10393371 :                         if ((cur = skip_white_space(lc)) == EOF)
    1156             :                                 return cur;
    1157    10371944 :                         continue;  /* try again */
    1158    20300072 :                 } else if (iswdigit(cur)) {
    1159      947154 :                         return number(c, cur);
    1160    19352918 :                 } else if (iswalpha(cur) || cur == '_') {
    1161    10328913 :                         switch (cur) {
    1162      506753 :                         case 'e': /* string with escapes */
    1163             :                         case 'E':
    1164      506753 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1165      506753 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '\'') {
    1166        3619 :                                         return scanner_string(c, scanner_getc(lc), true);
    1167             :                                 }
    1168             :                                 break;
    1169      309174 :                         case 'x': /* blob */
    1170             :                         case 'X':
    1171             :                         case 'r': /* raw string */
    1172             :                         case 'R':
    1173      309174 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1174      309174 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '\'') {
    1175        3159 :                                         return scanner_string(c, scanner_getc(lc), false);
    1176             :                                 }
    1177             :                                 break;
    1178      145523 :                         case 'u': /* unicode string */
    1179             :                         case 'U':
    1180      145523 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1181      145534 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '&' &&
    1182          11 :                                     scanner_read_more(lc, 2) != EOF &&
    1183          11 :                                     (lc->rs->buf[lc->rs->pos + lc->yycur + 1] == '\'' ||
    1184             :                                      lc->rs->buf[lc->rs->pos + lc->yycur + 1] == '"')) {
    1185          11 :                                         cur = scanner_getc(lc); /* '&' */
    1186          11 :                                         return scanner_string(c, scanner_getc(lc), false);
    1187             :                                 }
    1188             :                                 break;
    1189             :                         default:
    1190             :                                 break;
    1191             :                         }
    1192    10322124 :                         return keyword_or_ident(c, cur);
    1193     9024005 :                 } else if (iswpunct(cur)) {
    1194     9023982 :                         return scanner_symbol(c, cur);
    1195             :                 }
    1196          32 :                 if (cur == EOF) {
    1197           0 :                         if (lc->mode == LINE_1 || !lc->started )
    1198             :                                 return cur;
    1199           0 :                         return scanner_error(c, cur);
    1200             :                 }
    1201             :                 /* none of the above: error */
    1202          32 :                 return scanner_error(c, cur);
    1203             :         }
    1204             : }
    1205             : 
    1206             : /* SQL 'quoted' idents consist of a set of any character of
    1207             :  * the source language character set other than a 'quote'
    1208             :  *
    1209             :  * MonetDB has 3 restrictions:
    1210             :  *      1 we disallow '%' as the first character.
    1211             :  *      2 the length is limited to 1024 characters
    1212             :  *      3 the identifier 'TID%' is not allowed
    1213             :  */
    1214             : static bool
    1215      917599 : valid_ident(const char *restrict s, char *restrict dst)
    1216             : {
    1217             :         int p = 0;
    1218             : 
    1219      917599 :         if (*s == '%')
    1220             :                 return false;
    1221             : 
    1222     6795618 :         while (*s) {
    1223     5878019 :                 if ((dst[p++] = *s++) == '"' && *s == '"')
    1224          58 :                         s++;
    1225     5878019 :                 if (p >= 1024)
    1226             :                         return false;
    1227             :         }
    1228      917599 :         dst[p] = '\0';
    1229      917599 :         if (strcmp(dst, TID + 1) == 0) /* an index named 'TID%' could interfere with '%TID%' */
    1230           0 :                 return false;
    1231             :         return true;
    1232             : }
    1233             : 
    1234             : static inline int
    1235    20309539 : sql_get_next_token(YYSTYPE *yylval, void *parm)
    1236             : {
    1237             :         mvc *c = (mvc*)parm;
    1238    20309539 :         struct scanner *lc = &c->scanner;
    1239             :         int token = 0, cur = 0;
    1240             : 
    1241    20309539 :         if (lc->rs->buf == NULL) /* malloc failure */
    1242             :                 return EOF;
    1243             : 
    1244    20309539 :         if (lc->yynext) {
    1245             :                 int next = lc->yynext;
    1246             : 
    1247       49200 :                 lc->yynext = 0;
    1248       49200 :                 return(next);
    1249             :         }
    1250             : 
    1251    20260339 :         if (lc->yybak) {
    1252    19707358 :                 lc->rs->buf[lc->rs->pos + lc->yycur] = lc->yybak;
    1253    19707358 :                 lc->yybak = 0;
    1254             :         }
    1255             : 
    1256    20260339 :         lc->yysval = lc->yycur;
    1257    20260339 :         lc->yylast = lc->yyval;
    1258    20260339 :         cur = scanner_getc(lc);
    1259    20260339 :         if (cur < 0)
    1260             :                 return EOF;
    1261    20254845 :         token = tokenize(c, cur);
    1262             : 
    1263    20254845 :         yylval->sval = (lc->rs->buf + lc->rs->pos + lc->yysval);
    1264             : 
    1265             :         /* This is needed as ALIAS and aTYPE get defined too late, see
    1266             :            sql_keyword.h */
    1267    20254845 :         if (token == KW_ALIAS)
    1268             :                 token = ALIAS;
    1269             : 
    1270    20251256 :         if (token == KW_TYPE)
    1271             :                 token = aTYPE;
    1272             : 
    1273    20254845 :         if (token == IDENT || token == COMPARISON ||
    1274    15710717 :             token == RANK || token == aTYPE || token == ALIAS) {
    1275     4583691 :                 yylval->sval = sa_strndup(c->sa, yylval->sval, lc->yycur-lc->yysval);
    1276     4583691 :                 lc->next_string_is_raw = false;
    1277    15671154 :         } else if (token == STRING) {
    1278     1555683 :                 char quote = *yylval->sval;
    1279     1555683 :                 char *str = sa_alloc( c->sa, (lc->yycur-lc->yysval-2)*2 + 1 );
    1280             :                 char *dst;
    1281             : 
    1282     1555683 :                 assert(quote == '"' || quote == '\'' || quote == 'E' || quote == 'e' || quote == 'U' || quote == 'u' || quote == 'X' || quote == 'x' || quote == 'R' || quote == 'r');
    1283             : 
    1284     1555683 :                 lc->rs->buf[lc->rs->pos + lc->yycur - 1] = 0;
    1285     1555683 :                 switch (quote) {
    1286      917599 :                 case '"':
    1287      917599 :                         if (valid_ident(yylval->sval+1,str)) {
    1288             :                                 token = IDENT;
    1289             :                         } else {
    1290           0 :                                 sql_error(c, 1, SQLSTATE(42000) "Invalid identifier '%s'", yylval->sval+1);
    1291           0 :                                 return LEX_ERROR;
    1292             :                         }
    1293             :                         break;
    1294        3619 :                 case 'e':
    1295             :                 case 'E':
    1296        3619 :                         assert(yylval->sval[1] == '\'');
    1297        3619 :                         GDKstrFromStr((unsigned char *) str,
    1298             :                                       (unsigned char *) yylval->sval + 2,
    1299        3619 :                                       lc->yycur-lc->yysval - 2);
    1300             :                         quote = '\'';
    1301        3619 :                         break;
    1302          11 :                 case 'u':
    1303             :                 case 'U':
    1304          11 :                         assert(yylval->sval[1] == '&');
    1305          11 :                         assert(yylval->sval[2] == '\'' || yylval->sval[2] == '"');
    1306          11 :                         strcpy(str, yylval->sval + 3);
    1307          11 :                         token = yylval->sval[2] == '\'' ? USTRING : UIDENT;
    1308             :                         quote = yylval->sval[2];
    1309          11 :                         lc->next_string_is_raw = true;
    1310          11 :                         break;
    1311           1 :                 case 'x':
    1312             :                 case 'X':
    1313           1 :                         assert(yylval->sval[1] == '\'');
    1314             :                         dst = str;
    1315           5 :                         for (char *src = yylval->sval + 2; *src; dst++)
    1316           4 :                                 if ((*dst = *src++) == '\'' && *src == '\'')
    1317           0 :                                         src++;
    1318           1 :                         *dst = 0;
    1319             :                         quote = '\'';
    1320             :                         token = XSTRING;
    1321           1 :                         lc->next_string_is_raw = true;
    1322           1 :                         break;
    1323        3151 :                 case 'r':
    1324             :                 case 'R':
    1325        3151 :                         assert(yylval->sval[1] == '\'');
    1326             :                         dst = str;
    1327      411595 :                         for (char *src = yylval->sval + 2; *src; dst++)
    1328      408444 :                                 if ((*dst = *src++) == '\'' && *src == '\'')
    1329          41 :                                         src++;
    1330             :                         quote = '\'';
    1331        3151 :                         *dst = 0;
    1332        3151 :                         break;
    1333      631302 :                 default:
    1334      631302 :                         if (lc->raw_string_mode || lc->next_string_is_raw) {
    1335             :                                 dst = str;
    1336         172 :                                 for (char *src = yylval->sval + 1; *src; dst++)
    1337         150 :                                         if ((*dst = *src++) == '\'' && *src == '\'')
    1338           2 :                                                 src++;
    1339          22 :                                 *dst = 0;
    1340             :                         } else {
    1341      631280 :                                 GDKstrFromStr((unsigned char *)str,
    1342      631280 :                                               (unsigned char *)yylval->sval + 1,
    1343      631280 :                                               lc->yycur - lc->yysval - 1);
    1344             :                         }
    1345             :                         break;
    1346             :                 }
    1347     1555683 :                 yylval->sval = str;
    1348             : 
    1349             :                 /* reset original */
    1350     1555683 :                 lc->rs->buf[lc->rs->pos+lc->yycur- 1] = quote;
    1351             :         } else {
    1352    14115471 :                 lc->next_string_is_raw = false;
    1353             :         }
    1354             : 
    1355             :         return(token);
    1356             : }
    1357             : 
    1358             : /* also see sql_parser.y */
    1359             : extern int sqllex( YYSTYPE *yylval, void *m );
    1360             : 
    1361             : int
    1362    20283438 : sqllex(YYSTYPE * yylval, void *parm)
    1363             : {
    1364             :         int token;
    1365             :         mvc *c = (mvc *) parm;
    1366             :         struct scanner *lc = &c->scanner;
    1367             :         size_t pos;
    1368             : 
    1369             :         /* store position for when view's query ends */
    1370    20283440 :         pos = lc->rs->pos + lc->yycur;
    1371             : 
    1372    20283440 :         token = sql_get_next_token(yylval, parm);
    1373             : 
    1374    20283440 :         if (token == NOT) {
    1375       59913 :                 int next = sqllex(yylval, parm);
    1376             : 
    1377       59913 :                 if (next == NOT) {
    1378             :                         return sqllex(yylval, parm);
    1379       59911 :                 } else if (next == BETWEEN) {
    1380             :                         token = NOT_BETWEEN;
    1381       59026 :                 } else if (next == sqlIN) {
    1382             :                         token = NOT_IN;
    1383       49349 :                 } else if (next == LIKE) {
    1384             :                         token = NOT_LIKE;
    1385       49259 :                 } else if (next == ILIKE) {
    1386             :                         token = NOT_ILIKE;
    1387             :                 } else {
    1388       49200 :                         lc->yynext = next;
    1389             :                 }
    1390    20223527 :         } else if (token == SCOLON) {
    1391             :                 /* ignore semi-colon(s) following a semi-colon */
    1392      611482 :                 if (lc->yylast == SCOLON) {
    1393       26098 :                         size_t prev = lc->yycur;
    1394       26099 :                         while ((token = sql_get_next_token(yylval, parm)) == SCOLON)
    1395           1 :                                 prev = lc->yycur;
    1396             : 
    1397             :                         /* skip the skipped stuff also in the buffer */
    1398       26098 :                         lc->rs->pos += prev;
    1399       26098 :                         lc->yycur -= prev;
    1400             :                 }
    1401             :         }
    1402             : 
    1403    20283438 :         if (lc->log)
    1404           0 :                 mnstr_write(lc->log, lc->rs->buf+pos, lc->rs->pos + lc->yycur - pos, 1);
    1405             : 
    1406    20283438 :         lc->started += (token != EOF);
    1407             :         return token;
    1408             : }

Generated by: LCOV version 1.14