LCOV - code coverage report
Current view: top level - sql/server - sql_scan.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1134 1207 94.0 %
Date: 2025-03-26 20:06:40 Functions: 27 27 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024, 2025 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include <wctype.h>
      15             : #include "sql_mem.h"
      16             : #include "sql_scan.h"
      17             : #include "sql_types.h"
      18             : #include "sql_symbol.h"
      19             : #include "sql_mvc.h"
      20             : #include "sql_parser.tab.h"
      21             : #include "sql_semantic.h"
      22             : #include "sql_parser.h"               /* for sql_error() */
      23             : 
      24             : #include "stream.h"
      25             : #include "mapi_prompt.h"
      26             : #include <unistd.h>
      27             : #include <string.h>
      28             : #include <ctype.h>
      29             : #include "sql_keyword.h"
      30             : 
      31             : static char *
      32          17 : uescape_xform(char *restrict s, const char *restrict esc)
      33             : {
      34          17 :         size_t i, j;
      35             : 
      36          60 :         for (i = j = 0; s[i]; i++) {
      37          43 :                 if (s[i] == *esc) {
      38          43 :                         if (s[i + 1] == *esc) {
      39           0 :                                 s[j++] = *esc;
      40           0 :                                 i++;
      41             :                         } else {
      42          43 :                                 int c = 0;
      43          43 :                                 int n;
      44          43 :                                 if (s[i + 1] == '+') {
      45          26 :                                         n = 6;
      46          26 :                                         i++;
      47             :                                 } else {
      48             :                                         n = 4;
      49             :                                 }
      50         224 :                                 do {
      51         224 :                                         i++;
      52         224 :                                         c <<= 4;
      53         224 :                                         if ('0' <= s[i] && s[i] <= '9')
      54         170 :                                                 c |= s[i] - '0';
      55          54 :                                         else if ('a' <= s[i] && s[i] <= 'f')
      56          24 :                                                 c |= s[i] - 'a' + 10;
      57          30 :                                         else if ('A' <= s[i] && s[i] <= 'F')
      58          30 :                                                 c |= s[i] - 'A' + 10;
      59             :                                         else
      60             :                                                 return NULL;
      61         224 :                                 } while (--n > 0);
      62          43 :                                 if (c == 0 || c > 0x10FFFF || (c & 0xFFF800) == 0xD800)
      63             :                                         return NULL;
      64          43 :                                 if (c < 0x80) {
      65          14 :                                         s[j++] = c;
      66             :                                 } else {
      67          29 :                                         if (c < 0x800) {
      68           5 :                                                 s[j++] = 0xC0 | (c >> 6);
      69             :                                         } else {
      70          24 :                                                 if (c < 0x10000) {
      71          12 :                                                         s[j++] = 0xE0 | (c >> 12);
      72             :                                                 } else {
      73          12 :                                                         s[j++] = 0xF0 | (c >> 18);
      74          12 :                                                         s[j++] = 0x80 | ((c >> 12) & 0x3F);
      75             :                                                 }
      76          24 :                                                 s[j++] = 0x80 | ((c >> 6) & 0x3F);
      77             :                                         }
      78          29 :                                         s[j++] = 0x80 | (c & 0x3F);
      79             :                                 }
      80             :                         }
      81             :                 } else {
      82           0 :                         s[j++] = s[i];
      83             :                 }
      84             :         }
      85          17 :         s[j] = 0;
      86          17 :         return s;
      87             : }
      88             : 
      89             : /**
      90             :  * Removes all comments before the query. In query comments are kept.
      91             :  */
      92             : char *
      93      438941 : query_cleaned(allocator *sa, const char *query)
      94             : {
      95      438941 :         char *q, *r, *c = NULL;
      96      438941 :         int lines = 0;
      97      438941 :         int quote = 0;          /* inside quotes ('..', "..", {..}) */
      98      438941 :         bool bs = false;                /* seen a backslash in a quoted string */
      99      438941 :         bool incomment1 = false;        /* inside traditional C style comment */
     100      438941 :         bool incomment2 = false;        /* inside comment starting with --  */
     101      438941 :         bool inline_comment = false;
     102             : 
     103      438941 :         r = SA_NEW_ARRAY(sa, char, strlen(query) + 1);
     104      438938 :         if(!r)
     105             :                 return NULL;
     106             : 
     107    69985888 :         for (q = r; *query; query++) {
     108    69546950 :                 if (incomment1) {
     109       16396 :                         if (*query == '/' && query[-1] == '*') {
     110         237 :                                 incomment1 = false;
     111         237 :                                 if (c == r && lines > 0) {
     112         229 :                                         q = r; // reset to beginning
     113         229 :                                         lines = 0;
     114         229 :                                         continue;
     115             :                                 }
     116             :                         }
     117       16167 :                         if (*query == '\n') lines++;
     118       16167 :                         *q++ = *query;
     119    69530554 :                 } else if (incomment2) {
     120      831472 :                         if (*query == '\n') {
     121        2916 :                                 incomment2 = false;
     122        2916 :                                 inline_comment = false;
     123             :                                 /* add newline only if comment doesn't
     124             :                                  * occupy whole line */
     125        2916 :                                 if (q > r && q[-1] != '\n'){
     126        1000 :                                         *q++ = '\n';
     127        1000 :                                         lines++;
     128             :                                 }
     129      828556 :                         } else if (inline_comment){
     130       24007 :                                 *q++ = *query; // preserve in line query comments
     131             :                         }
     132    68699082 :                 } else if (quote) {
     133    22397764 :                         if (bs) {
     134             :                                 bs = false;
     135    22394431 :                         } else if (*query == '\\') {
     136             :                                 bs = true;
     137    22391098 :                         } else if (*query == quote) {
     138      690268 :                                 quote = 0;
     139             :                         }
     140    22397764 :                         *q++ = *query;
     141    46301318 :                 } else if (*query == '"' || *query == '\'') {
     142      689800 :                         quote = *query;
     143      689800 :                         *q++ = *query;
     144    45611518 :                 } else if (*query == '{') {
     145         513 :                         quote = '}';
     146         513 :                         *q++ = *query;
     147    45611005 :                 } else if (*query == '-' && query[1] == '-') {
     148        2916 :                         if (q > r && q[-1] != '\n') {
     149        1000 :                                 inline_comment = true;
     150        1000 :                                 *q++ = *query; // preserve in line query comments
     151             :                         }
     152             :                         incomment2 = true;
     153    45608089 :                 } else if (*query == '/' && query[1] == '*') {
     154         237 :                         incomment1 = true;
     155         237 :                         c = q;
     156         237 :                         *q++ = *query;
     157    45607852 :                 } else if (*query == '\n') {
     158             :                         /* collapse newlines */
     159      907305 :                         if (q > r && q[-1] != '\n') {
     160      865324 :                                 *q++ = '\n';
     161      865324 :                                 lines++;
     162             :                         }
     163    44700547 :                 } else if (*query == ' ' || *query == '\t') {
     164             :                         /* collapse white space */
     165     7192357 :                         if (q > r && q[-1] != ' ')
     166     5705268 :                                 *q++ = ' ';
     167             :                 } else {
     168    37508190 :                         *q++ = *query;
     169             :                 }
     170             :         }
     171      438938 :         *q = 0;
     172      438938 :         return r;
     173             : }
     174             : 
     175             : int
     176         357 : scanner_init_keywords(void)
     177             : {
     178         357 :         int failed = 0;
     179             : 
     180         357 :         failed += keywords_insert("false", BOOL_FALSE);
     181         357 :         failed += keywords_insert("true", BOOL_TRUE);
     182         357 :         failed += keywords_insert("bool", sqlBOOL);
     183             : 
     184         357 :         failed += keywords_insert("ALTER", ALTER);
     185         357 :         failed += keywords_insert("ADD", ADD);
     186         357 :         failed += keywords_insert("AND", AND);
     187             : 
     188         357 :         failed += keywords_insert("RANK", RANK);
     189         357 :         failed += keywords_insert("DENSE_RANK", RANK);
     190         357 :         failed += keywords_insert("PERCENT_RANK", RANK);
     191         357 :         failed += keywords_insert("CUME_DIST", RANK);
     192         357 :         failed += keywords_insert("ROW_NUMBER", RANK);
     193         357 :         failed += keywords_insert("NTILE", RANK);
     194         357 :         failed += keywords_insert("LAG", RANK);
     195         357 :         failed += keywords_insert("LEAD", RANK);
     196         357 :         failed += keywords_insert("FETCH", FETCH);
     197         357 :         failed += keywords_insert("FIRST_VALUE", RANK);
     198         357 :         failed += keywords_insert("LAST_VALUE", RANK);
     199         357 :         failed += keywords_insert("NTH_VALUE", RANK);
     200             : 
     201         357 :         failed += keywords_insert("BEST", BEST);
     202         357 :         failed += keywords_insert("EFFORT", EFFORT);
     203             : 
     204         357 :         failed += keywords_insert("AS", AS);
     205         357 :         failed += keywords_insert("ASC", ASC);
     206         357 :         failed += keywords_insert("AUTHORIZATION", AUTHORIZATION);
     207         357 :         failed += keywords_insert("BETWEEN", BETWEEN);
     208         357 :         failed += keywords_insert("SYMMETRIC", SYMMETRIC);
     209         357 :         failed += keywords_insert("ASYMMETRIC", ASYMMETRIC);
     210         357 :         failed += keywords_insert("BY", BY);
     211         357 :         failed += keywords_insert("CAST", CAST);
     212         357 :         failed += keywords_insert("CONVERT", CONVERT);
     213         357 :         failed += keywords_insert("CHARACTER", CHARACTER);
     214         357 :         failed += keywords_insert("CHAR", CHARACTER);
     215         357 :         failed += keywords_insert("VARYING", VARYING);
     216         357 :         failed += keywords_insert("VARCHAR", VARCHAR);
     217         357 :         failed += keywords_insert("BINARY", BINARY);
     218         357 :         failed += keywords_insert("LARGE", LARGE);
     219         357 :         failed += keywords_insert("OBJECT", OBJECT);
     220         357 :         failed += keywords_insert("CLOB", CLOB);
     221         357 :         failed += keywords_insert("BLOB", sqlBLOB);
     222         357 :         failed += keywords_insert("TEXT", sqlTEXT);
     223         357 :         failed += keywords_insert("TINYTEXT", sqlTEXT);
     224         357 :         failed += keywords_insert("STRING", CLOB);    /* ? */
     225         357 :         failed += keywords_insert("CHECK", CHECK);
     226         357 :         failed += keywords_insert("CLIENT", CLIENT);
     227         357 :         failed += keywords_insert("SERVER", SERVER);
     228         357 :         failed += keywords_insert("COMMENT", COMMENT);
     229         357 :         failed += keywords_insert("CONSTRAINT", CONSTRAINT);
     230         357 :         failed += keywords_insert("CREATE", CREATE);
     231         357 :         failed += keywords_insert("CROSS", CROSS);
     232         357 :         failed += keywords_insert("COPY", COPY);
     233         357 :         failed += keywords_insert("RECORDS", RECORDS);
     234         357 :         failed += keywords_insert("DELIMITERS", DELIMITERS);
     235         357 :         failed += keywords_insert("STDIN", STDIN);
     236         357 :         failed += keywords_insert("STDOUT", STDOUT);
     237             : 
     238         357 :         failed += keywords_insert("TINYINT", TINYINT);
     239         357 :         failed += keywords_insert("SMALLINT", SMALLINT);
     240         357 :         failed += keywords_insert("INTEGER", sqlINTEGER);
     241         357 :         failed += keywords_insert("INT", sqlINTEGER);
     242         357 :         failed += keywords_insert("MEDIUMINT", sqlINTEGER);
     243         357 :         failed += keywords_insert("BIGINT", BIGINT);
     244             : #ifdef HAVE_HGE
     245         357 :         failed += keywords_insert("HUGEINT", HUGEINT);
     246             : #endif
     247         357 :         failed += keywords_insert("DEC", sqlDECIMAL);
     248         357 :         failed += keywords_insert("DECIMAL", sqlDECIMAL);
     249         357 :         failed += keywords_insert("NUMERIC", sqlDECIMAL);
     250         357 :         failed += keywords_insert("DECLARE", DECLARE);
     251         357 :         failed += keywords_insert("DEFAULT", DEFAULT);
     252         357 :         failed += keywords_insert("DESC", DESC);
     253         357 :         failed += keywords_insert("DISTINCT", DISTINCT);
     254         357 :         failed += keywords_insert("DOUBLE", sqlDOUBLE);
     255         357 :         failed += keywords_insert("REAL", sqlREAL);
     256         357 :         failed += keywords_insert("DROP", DROP);
     257         357 :         failed += keywords_insert("ESCAPE", ESCAPE);
     258         357 :         failed += keywords_insert("EXISTS", EXISTS);
     259         357 :         failed += keywords_insert("UESCAPE", UESCAPE);
     260         357 :         failed += keywords_insert("EXTRACT", EXTRACT);
     261         357 :         failed += keywords_insert("FLOAT", sqlFLOAT);
     262         357 :         failed += keywords_insert("FOR", FOR);
     263         357 :         failed += keywords_insert("FOREIGN", FOREIGN);
     264         357 :         failed += keywords_insert("FROM", FROM);
     265         357 :         failed += keywords_insert("FWF", FWF);
     266             : 
     267         357 :         failed += keywords_insert("BIG", BIG);
     268         357 :         failed += keywords_insert("LITTLE", LITTLE);
     269         357 :         failed += keywords_insert("NATIVE", NATIVE);
     270         357 :         failed += keywords_insert("ENDIAN", ENDIAN);
     271             : 
     272         357 :         failed += keywords_insert("REFERENCES", REFERENCES);
     273             : 
     274         357 :         failed += keywords_insert("MATCH", MATCH);
     275         357 :         failed += keywords_insert("FULL", FULL);
     276         357 :         failed += keywords_insert("PARTIAL", PARTIAL);
     277         357 :         failed += keywords_insert("SIMPLE", SIMPLE);
     278             : 
     279         357 :         failed += keywords_insert("INSERT", INSERT);
     280         357 :         failed += keywords_insert("UPDATE", UPDATE);
     281         357 :         failed += keywords_insert("DELETE", sqlDELETE);
     282         357 :         failed += keywords_insert("TRUNCATE", TRUNCATE);
     283         357 :         failed += keywords_insert("MATCHED", MATCHED);
     284             : 
     285         357 :         failed += keywords_insert("ACTION", ACTION);
     286         357 :         failed += keywords_insert("CASCADE", CASCADE);
     287         357 :         failed += keywords_insert("RESTRICT", RESTRICT);
     288         357 :         failed += keywords_insert("FIRST", FIRST);
     289         357 :         failed += keywords_insert("GLOBAL", GLOBAL);
     290         357 :         failed += keywords_insert("GROUP", sqlGROUP);
     291         357 :         failed += keywords_insert("GROUPING", GROUPING);
     292         357 :         failed += keywords_insert("ROLLUP", ROLLUP);
     293         357 :         failed += keywords_insert("CUBE", CUBE);
     294         357 :         failed += keywords_insert("HAVING", HAVING);
     295         357 :         failed += keywords_insert("ILIKE", ILIKE);
     296         357 :         failed += keywords_insert("IMPRINTS", IMPRINTS);
     297         357 :         failed += keywords_insert("IN", sqlIN);
     298         357 :         failed += keywords_insert("INNER", INNER);
     299         357 :         failed += keywords_insert("INTO", INTO);
     300         357 :         failed += keywords_insert("IS", IS);
     301         357 :         failed += keywords_insert("JOIN", JOIN);
     302         357 :         failed += keywords_insert("KEY", KEY);
     303         357 :         failed += keywords_insert("LATERAL", LATERAL);
     304         357 :         failed += keywords_insert("LEFT", LEFT);
     305         357 :         failed += keywords_insert("LIKE", LIKE);
     306         357 :         failed += keywords_insert("LIMIT", LIMIT);
     307         357 :         failed += keywords_insert("SAMPLE", SAMPLE);
     308         357 :         failed += keywords_insert("SEED", SEED);
     309         357 :         failed += keywords_insert("LAST", LAST);
     310         357 :         failed += keywords_insert("LOCAL", LOCAL);
     311         357 :         failed += keywords_insert("NATURAL", NATURAL);
     312         357 :         failed += keywords_insert("NOT", NOT);
     313         357 :         failed += keywords_insert("NULL", sqlNULL);
     314         357 :         failed += keywords_insert("NULLS", NULLS);
     315         357 :         failed += keywords_insert("OFFSET", OFFSET);
     316         357 :         failed += keywords_insert("ON", ON);
     317         357 :         failed += keywords_insert("OPTIONS", OPTIONS);
     318         357 :         failed += keywords_insert("OPTION", OPTION);
     319         357 :         failed += keywords_insert("OR", OR);
     320         357 :         failed += keywords_insert("ORDER", ORDER);
     321         357 :         failed += keywords_insert("ORDERED", ORDERED);
     322         357 :         failed += keywords_insert("OUTER", OUTER);
     323         357 :         failed += keywords_insert("OVER", OVER);
     324         357 :         failed += keywords_insert("PARTITION", PARTITION);
     325         357 :         failed += keywords_insert("PATH", PATH);
     326         357 :         failed += keywords_insert("PRECISION", PRECISION);
     327         357 :         failed += keywords_insert("PRIMARY", PRIMARY);
     328             : 
     329         357 :         failed += keywords_insert("USER", USER);
     330         357 :         failed += keywords_insert("RENAME", RENAME);
     331         357 :         failed += keywords_insert("UNENCRYPTED", UNENCRYPTED);
     332         357 :         failed += keywords_insert("ENCRYPTED", ENCRYPTED);
     333         357 :         failed += keywords_insert("PASSWORD", PASSWORD);
     334         357 :         failed += keywords_insert("GRANT", GRANT);
     335         357 :         failed += keywords_insert("REVOKE", REVOKE);
     336         357 :         failed += keywords_insert("ROLE", ROLE);
     337         357 :         failed += keywords_insert("ADMIN", ADMIN);
     338         357 :         failed += keywords_insert("PRIVILEGES", PRIVILEGES);
     339         357 :         failed += keywords_insert("PUBLIC", PUBLIC);
     340         357 :         failed += keywords_insert("CURRENT_USER", CURRENT_USER);
     341         357 :         failed += keywords_insert("CURRENT_ROLE", CURRENT_ROLE);
     342         357 :         failed += keywords_insert("SESSION_USER", SESSION_USER);
     343         357 :         failed += keywords_insert("CURRENT_SCHEMA", CURRENT_SCHEMA);
     344         357 :         failed += keywords_insert("SESSION", sqlSESSION);
     345         357 :         failed += keywords_insert("MAX_MEMORY", MAX_MEMORY);
     346         357 :         failed += keywords_insert("MAX_WORKERS", MAX_WORKERS);
     347         357 :         failed += keywords_insert("OPTIMIZER", OPTIMIZER);
     348             : 
     349         357 :         failed += keywords_insert("RIGHT", RIGHT);
     350         357 :         failed += keywords_insert("SCHEMA", SCHEMA);
     351         357 :         failed += keywords_insert("SELECT", SELECT);
     352         357 :         failed += keywords_insert("SET", SET);
     353         357 :         failed += keywords_insert("SETS", SETS);
     354         357 :         failed += keywords_insert("AUTO_COMMIT", AUTO_COMMIT);
     355             : 
     356         357 :         failed += keywords_insert("ALL", ALL);
     357         357 :         failed += keywords_insert("ANY", ANY);
     358         357 :         failed += keywords_insert("SOME", SOME);
     359         357 :         failed += keywords_insert("EVERY", ANY);
     360             :         /*
     361             :            failed += keywords_insert("SQLCODE", SQLCODE );
     362             :          */
     363         357 :         failed += keywords_insert("COLUMN", COLUMN);
     364         357 :         failed += keywords_insert("TABLE", TABLE);
     365         357 :         failed += keywords_insert("TEMPORARY", TEMPORARY);
     366         357 :         failed += keywords_insert("TEMP", TEMP);
     367         357 :         failed += keywords_insert("REMOTE", REMOTE);
     368         357 :         failed += keywords_insert("MERGE", MERGE);
     369         357 :         failed += keywords_insert("REPLICA", REPLICA);
     370         357 :         failed += keywords_insert("UNLOGGED", UNLOGGED);
     371         357 :         failed += keywords_insert("TO", TO);
     372         357 :         failed += keywords_insert("UNION", UNION);
     373         357 :         failed += keywords_insert("EXCEPT", EXCEPT);
     374         357 :         failed += keywords_insert("INTERSECT", INTERSECT);
     375         357 :         failed += keywords_insert("CORRESPONDING", CORRESPONDING);
     376         357 :         failed += keywords_insert("UNIQUE", UNIQUE);
     377         357 :         failed += keywords_insert("USING", USING);
     378         357 :         failed += keywords_insert("VALUES", VALUES);
     379         357 :         failed += keywords_insert("VIEW", VIEW);
     380         357 :         failed += keywords_insert("WHERE", WHERE);
     381         357 :         failed += keywords_insert("WITH", WITH);
     382         357 :         failed += keywords_insert("WITHIN", WITHIN);
     383         357 :         failed += keywords_insert("WITHOUT", WITHOUT);
     384         357 :         failed += keywords_insert("DATA", DATA);
     385             : 
     386         357 :         failed += keywords_insert("DATE", sqlDATE);
     387         357 :         failed += keywords_insert("TIME", TIME);
     388         357 :         failed += keywords_insert("TIMESTAMP", TIMESTAMP);
     389         357 :         failed += keywords_insert("INTERVAL", INTERVAL);
     390         357 :         failed += keywords_insert("CURRENT_DATE", CURRENT_DATE);
     391         357 :         failed += keywords_insert("CURRENT_TIME", CURRENT_TIME);
     392         357 :         failed += keywords_insert("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP);
     393         357 :         failed += keywords_insert("CURRENT_TIMEZONE", CURRENT_TIMEZONE);
     394         357 :         failed += keywords_insert("NOW", CURRENT_TIMESTAMP);
     395         357 :         failed += keywords_insert("LOCALTIME", LOCALTIME);
     396         357 :         failed += keywords_insert("LOCALTIMESTAMP", LOCALTIMESTAMP);
     397         357 :         failed += keywords_insert("ZONE", ZONE);
     398             : 
     399         357 :         failed += keywords_insert("CENTURY", CENTURY);
     400         357 :         failed += keywords_insert("DECADE", DECADE);
     401         357 :         failed += keywords_insert("YEAR", YEAR);
     402         357 :         failed += keywords_insert("QUARTER", QUARTER);
     403         357 :         failed += keywords_insert("MONTH", MONTH);
     404         357 :         failed += keywords_insert("WEEK", WEEK);
     405         357 :         failed += keywords_insert("DOW", DOW);
     406         357 :         failed += keywords_insert("DOY", DOY);
     407         357 :         failed += keywords_insert("DAY", DAY);
     408         357 :         failed += keywords_insert("HOUR", HOUR);
     409         357 :         failed += keywords_insert("MINUTE", MINUTE);
     410         357 :         failed += keywords_insert("SECOND", SECOND);
     411         357 :         failed += keywords_insert("EPOCH", EPOCH);
     412             : 
     413         357 :         failed += keywords_insert("POSITION", POSITION);
     414         357 :         failed += keywords_insert("SUBSTRING", SUBSTRING);
     415         357 :         failed += keywords_insert("SPLIT_PART", SPLIT_PART);
     416         357 :         failed += keywords_insert("TRIM", TRIM);
     417         357 :         failed += keywords_insert("LEADING", LEADING);
     418         357 :         failed += keywords_insert("TRAILING", TRAILING);
     419         357 :         failed += keywords_insert("BOTH", BOTH);
     420             : 
     421         357 :         failed += keywords_insert("CASE", CASE);
     422         357 :         failed += keywords_insert("WHEN", WHEN);
     423         357 :         failed += keywords_insert("THEN", THEN);
     424         357 :         failed += keywords_insert("ELSE", ELSE);
     425         357 :         failed += keywords_insert("END", END);
     426         357 :         failed += keywords_insert("NULLIF", NULLIF);
     427         357 :         failed += keywords_insert("COALESCE", COALESCE);
     428         357 :         failed += keywords_insert("ELSEIF", ELSEIF);
     429         357 :         failed += keywords_insert("IF", IF);
     430         357 :         failed += keywords_insert("WHILE", WHILE);
     431         357 :         failed += keywords_insert("DO", DO);
     432             : 
     433         357 :         failed += keywords_insert("COMMIT", COMMIT);
     434         357 :         failed += keywords_insert("ROLLBACK", ROLLBACK);
     435         357 :         failed += keywords_insert("SAVEPOINT", SAVEPOINT);
     436         357 :         failed += keywords_insert("RELEASE", RELEASE);
     437         357 :         failed += keywords_insert("WORK", WORK);
     438         357 :         failed += keywords_insert("CHAIN", CHAIN);
     439         357 :         failed += keywords_insert("PRESERVE", PRESERVE);
     440         357 :         failed += keywords_insert("ROWS", ROWS);
     441         357 :         failed += keywords_insert("NO", NO);
     442         357 :         failed += keywords_insert("START", START);
     443         357 :         failed += keywords_insert("TRANSACTION", TRANSACTION);
     444         357 :         failed += keywords_insert("READ", READ);
     445         357 :         failed += keywords_insert("WRITE", WRITE);
     446         357 :         failed += keywords_insert("ONLY", ONLY);
     447         357 :         failed += keywords_insert("ISOLATION", ISOLATION);
     448         357 :         failed += keywords_insert("LEVEL", LEVEL);
     449         357 :         failed += keywords_insert("UNCOMMITTED", UNCOMMITTED);
     450         357 :         failed += keywords_insert("COMMITTED", COMMITTED);
     451         357 :         failed += keywords_insert("REPEATABLE", sqlREPEATABLE);
     452         357 :         failed += keywords_insert("SNAPSHOT", SNAPSHOT);
     453         357 :         failed += keywords_insert("SERIALIZABLE", SERIALIZABLE);
     454         357 :         failed += keywords_insert("DIAGNOSTICS", DIAGNOSTICS);
     455         357 :         failed += keywords_insert("SIZE", sqlSIZE);
     456         357 :         failed += keywords_insert("STORAGE", STORAGE);
     457             : 
     458         357 :         failed += keywords_insert("TYPE", TYPE);
     459         357 :         failed += keywords_insert("PROCEDURE", PROCEDURE);
     460         357 :         failed += keywords_insert("FUNCTION", FUNCTION);
     461         357 :         failed += keywords_insert("LOADER", sqlLOADER);
     462         357 :         failed += keywords_insert("REPLACE", REPLACE);
     463             : 
     464             :         //failed += keywords_insert("FIELD", FIELD);
     465         357 :         failed += keywords_insert("FILTER", FILTER);
     466         357 :         failed += keywords_insert("AGGREGATE", AGGREGATE);
     467         357 :         failed += keywords_insert("RETURNS", RETURNS);
     468         357 :         failed += keywords_insert("EXTERNAL", EXTERNAL);
     469         357 :         failed += keywords_insert("NAME", sqlNAME);
     470         357 :         failed += keywords_insert("RETURN", RETURN);
     471         357 :         failed += keywords_insert("CALL", CALL);
     472         357 :         failed += keywords_insert("LANGUAGE", LANGUAGE);
     473             : 
     474         357 :         failed += keywords_insert("ANALYZE", ANALYZE);
     475         357 :         failed += keywords_insert("EXPLAIN", SQL_EXPLAIN);
     476         357 :         failed += keywords_insert("PLAN", SQL_PLAN);
     477         357 :         failed += keywords_insert("TRACE", SQL_TRACE);
     478         357 :         failed += keywords_insert("PREPARE", PREPARE);
     479         357 :         failed += keywords_insert("PREP", PREP);
     480         357 :         failed += keywords_insert("EXECUTE", EXECUTE);
     481         357 :         failed += keywords_insert("EXEC", EXEC);
     482         357 :         failed += keywords_insert("DEALLOCATE", DEALLOCATE);
     483             : 
     484         357 :         failed += keywords_insert("INDEX", INDEX);
     485             : 
     486         357 :         failed += keywords_insert("SEQUENCE", SEQUENCE);
     487         357 :         failed += keywords_insert("RESTART", RESTART);
     488         357 :         failed += keywords_insert("INCREMENT", INCREMENT);
     489         357 :         failed += keywords_insert("MAXVALUE", MAXVALUE);
     490         357 :         failed += keywords_insert("MINVALUE", MINVALUE);
     491         357 :         failed += keywords_insert("CYCLE", CYCLE);
     492         357 :         failed += keywords_insert("CACHE", CACHE);
     493         357 :         failed += keywords_insert("NEXT", NEXT);
     494         357 :         failed += keywords_insert("VALUE", VALUE);
     495         357 :         failed += keywords_insert("GENERATED", GENERATED);
     496         357 :         failed += keywords_insert("ALWAYS", ALWAYS);
     497         357 :         failed += keywords_insert("IDENTITY", IDENTITY);
     498         357 :         failed += keywords_insert("SERIAL", SERIAL);
     499         357 :         failed += keywords_insert("BIGSERIAL", BIGSERIAL);
     500         357 :         failed += keywords_insert("AUTO_INCREMENT", AUTO_INCREMENT);
     501         357 :         failed += keywords_insert("CONTINUE", CONTINUE);
     502             : 
     503         357 :         failed += keywords_insert("TRIGGER", TRIGGER);
     504         357 :         failed += keywords_insert("ATOMIC", ATOMIC);
     505         357 :         failed += keywords_insert("BEGIN", BEGIN);
     506         357 :         failed += keywords_insert("OF", OF);
     507         357 :         failed += keywords_insert("BEFORE", BEFORE);
     508         357 :         failed += keywords_insert("AFTER", AFTER);
     509         357 :         failed += keywords_insert("ROW", ROW);
     510         357 :         failed += keywords_insert("STATEMENT", STATEMENT);
     511         357 :         failed += keywords_insert("NEW", sqlNEW);
     512         357 :         failed += keywords_insert("OLD", OLD);
     513         357 :         failed += keywords_insert("EACH", EACH);
     514         357 :         failed += keywords_insert("REFERENCING", REFERENCING);
     515             : 
     516         357 :         failed += keywords_insert("RANGE", RANGE);
     517         357 :         failed += keywords_insert("UNBOUNDED", UNBOUNDED);
     518         357 :         failed += keywords_insert("PRECEDING", PRECEDING);
     519         357 :         failed += keywords_insert("FOLLOWING", FOLLOWING);
     520         357 :         failed += keywords_insert("CURRENT", CURRENT);
     521         357 :         failed += keywords_insert("EXCLUDE", EXCLUDE);
     522         357 :         failed += keywords_insert("OTHERS", OTHERS);
     523         357 :         failed += keywords_insert("TIES", TIES);
     524         357 :         failed += keywords_insert("GROUPS", GROUPS);
     525         357 :         failed += keywords_insert("WINDOW", WINDOW);
     526         357 :         failed += keywords_insert("QUALIFY", QUALIFY);
     527             : 
     528             :         /* special SQL/XML keywords */
     529         357 :         failed += keywords_insert("XMLCOMMENT", XMLCOMMENT);
     530         357 :         failed += keywords_insert("XMLCONCAT", XMLCONCAT);
     531         357 :         failed += keywords_insert("XMLDOCUMENT", XMLDOCUMENT);
     532         357 :         failed += keywords_insert("XMLELEMENT", XMLELEMENT);
     533         357 :         failed += keywords_insert("XMLATTRIBUTES", XMLATTRIBUTES);
     534         357 :         failed += keywords_insert("XMLFOREST", XMLFOREST);
     535         357 :         failed += keywords_insert("XMLPARSE", XMLPARSE);
     536         357 :         failed += keywords_insert("STRIP", STRIP);
     537         357 :         failed += keywords_insert("WHITESPACE", WHITESPACE);
     538         357 :         failed += keywords_insert("XMLPI", XMLPI);
     539         357 :         failed += keywords_insert("XMLQUERY", XMLQUERY);
     540         357 :         failed += keywords_insert("PASSING", PASSING);
     541         357 :         failed += keywords_insert("XMLTEXT", XMLTEXT);
     542         357 :         failed += keywords_insert("NIL", NIL);
     543         357 :         failed += keywords_insert("REF", REF);
     544         357 :         failed += keywords_insert("ABSENT", ABSENT);
     545         357 :         failed += keywords_insert("DOCUMENT", DOCUMENT);
     546         357 :         failed += keywords_insert("ELEMENT", ELEMENT);
     547         357 :         failed += keywords_insert("CONTENT", CONTENT);
     548         357 :         failed += keywords_insert("XMLNAMESPACES", XMLNAMESPACES);
     549         357 :         failed += keywords_insert("NAMESPACE", NAMESPACE);
     550         357 :         failed += keywords_insert("XMLVALIDATE", XMLVALIDATE);
     551         357 :         failed += keywords_insert("RETURNING", RETURNING);
     552         357 :         failed += keywords_insert("RECURSIVE", RECURSIVE);
     553         357 :         failed += keywords_insert("LOCATION", LOCATION);
     554         357 :         failed += keywords_insert("ID", ID);
     555         357 :         failed += keywords_insert("ACCORDING", ACCORDING);
     556         357 :         failed += keywords_insert("XMLSCHEMA", XMLSCHEMA);
     557         357 :         failed += keywords_insert("URI", URI);
     558         357 :         failed += keywords_insert("XMLAGG", XMLAGG);
     559             : 
     560             :         /* keywords for opengis */
     561         357 :         failed += keywords_insert("GEOMETRY", GEOMETRY);
     562             : 
     563         357 :         failed += keywords_insert("POINT", GEOMETRYSUBTYPE);
     564         357 :         failed += keywords_insert("LINESTRING", GEOMETRYSUBTYPE);
     565         357 :         failed += keywords_insert("POLYGON", GEOMETRYSUBTYPE);
     566         357 :         failed += keywords_insert("MULTIPOINT", GEOMETRYSUBTYPE);
     567         357 :         failed += keywords_insert("MULTILINESTRING", GEOMETRYSUBTYPE);
     568         357 :         failed += keywords_insert("MULTIPOLYGON", GEOMETRYSUBTYPE);
     569         357 :         failed += keywords_insert("GEOMETRYCOLLECTION", GEOMETRYSUBTYPE);
     570             : 
     571         357 :         failed += keywords_insert("POINTZ", GEOMETRYSUBTYPE);
     572         357 :         failed += keywords_insert("LINESTRINGZ", GEOMETRYSUBTYPE);
     573         357 :         failed += keywords_insert("POLYGONZ", GEOMETRYSUBTYPE);
     574         357 :         failed += keywords_insert("MULTIPOINTZ", GEOMETRYSUBTYPE);
     575         357 :         failed += keywords_insert("MULTILINESTRINGZ", GEOMETRYSUBTYPE);
     576         357 :         failed += keywords_insert("MULTIPOLYGONZ", GEOMETRYSUBTYPE);
     577         357 :         failed += keywords_insert("GEOMETRYCOLLECTIONZ", GEOMETRYSUBTYPE);
     578             : 
     579         357 :         failed += keywords_insert("POINTM", GEOMETRYSUBTYPE);
     580         357 :         failed += keywords_insert("LINESTRINGM", GEOMETRYSUBTYPE);
     581         357 :         failed += keywords_insert("POLYGONM", GEOMETRYSUBTYPE);
     582         357 :         failed += keywords_insert("MULTIPOINTM", GEOMETRYSUBTYPE);
     583         357 :         failed += keywords_insert("MULTILINESTRINGM", GEOMETRYSUBTYPE);
     584         357 :         failed += keywords_insert("MULTIPOLYGONM", GEOMETRYSUBTYPE);
     585         357 :         failed += keywords_insert("GEOMETRYCOLLECTIONM", GEOMETRYSUBTYPE);
     586             : 
     587         357 :         failed += keywords_insert("POINTZM", GEOMETRYSUBTYPE);
     588         357 :         failed += keywords_insert("LINESTRINGZM", GEOMETRYSUBTYPE);
     589         357 :         failed += keywords_insert("POLYGONZM", GEOMETRYSUBTYPE);
     590         357 :         failed += keywords_insert("MULTIPOINTZM", GEOMETRYSUBTYPE);
     591         357 :         failed += keywords_insert("MULTILINESTRINGZM", GEOMETRYSUBTYPE);
     592         357 :         failed += keywords_insert("MULTIPOLYGONZM", GEOMETRYSUBTYPE);
     593         357 :         failed += keywords_insert("GEOMETRYCOLLECTIONZM", GEOMETRYSUBTYPE);
     594         357 :         failed += keywords_insert("LOGIN", LOGIN);
     595             :         // odbc keywords
     596         357 :         failed += keywords_insert("d", ODBC_DATE_ESCAPE_PREFIX);
     597         357 :         failed += keywords_insert("t", ODBC_TIME_ESCAPE_PREFIX);
     598         357 :         failed += keywords_insert("ts", ODBC_TIMESTAMP_ESCAPE_PREFIX);
     599         357 :         failed += keywords_insert("guid", ODBC_GUID_ESCAPE_PREFIX);
     600         357 :         failed += keywords_insert("fn", ODBC_FUNC_ESCAPE_PREFIX);
     601         357 :         failed += keywords_insert("oj", ODBC_OJ_ESCAPE_PREFIX);
     602         357 :         failed += keywords_insert("DAYNAME", DAYNAME);
     603         357 :         failed += keywords_insert("IFNULL", IFNULL);
     604         357 :         failed += keywords_insert("MONTHNAME", MONTHNAME);
     605         357 :         failed += keywords_insert("TIMESTAMPADD", TIMESTAMPADD);
     606         357 :         failed += keywords_insert("TIMESTAMPDIFF", TIMESTAMPDIFF);
     607         357 :         failed += keywords_insert("SQL_BIGINT", SQL_BIGINT);
     608         357 :         failed += keywords_insert("SQL_BINARY", SQL_BINARY);
     609         357 :         failed += keywords_insert("SQL_BIT", SQL_BIT);
     610         357 :         failed += keywords_insert("SQL_CHAR", SQL_CHAR);
     611         357 :         failed += keywords_insert("SQL_DATE", SQL_DATE);
     612         357 :         failed += keywords_insert("SQL_DECIMAL", SQL_DECIMAL);
     613         357 :         failed += keywords_insert("SQL_DOUBLE", SQL_DOUBLE);
     614         357 :         failed += keywords_insert("SQL_FLOAT", SQL_FLOAT);
     615         357 :         failed += keywords_insert("SQL_GUID", SQL_GUID);
     616         357 :         failed += keywords_insert("SQL_HUGEINT", SQL_HUGEINT);
     617         357 :         failed += keywords_insert("SQL_INTEGER", SQL_INTEGER);
     618         357 :         failed += keywords_insert("SQL_INTERVAL_DAY", SQL_INTERVAL_DAY);
     619         357 :         failed += keywords_insert("SQL_INTERVAL_DAY_TO_HOUR", SQL_INTERVAL_DAY_TO_HOUR);
     620         357 :         failed += keywords_insert("SQL_INTERVAL_DAY_TO_MINUTE", SQL_INTERVAL_DAY_TO_MINUTE);
     621         357 :         failed += keywords_insert("SQL_INTERVAL_DAY_TO_SECOND", SQL_INTERVAL_DAY_TO_SECOND);
     622         357 :         failed += keywords_insert("SQL_INTERVAL_HOUR", SQL_INTERVAL_HOUR);
     623         357 :         failed += keywords_insert("SQL_INTERVAL_HOUR_TO_MINUTE", SQL_INTERVAL_HOUR_TO_MINUTE);
     624         357 :         failed += keywords_insert("SQL_INTERVAL_HOUR_TO_SECOND", SQL_INTERVAL_HOUR_TO_SECOND);
     625         357 :         failed += keywords_insert("SQL_INTERVAL_MINUTE", SQL_INTERVAL_MINUTE);
     626         357 :         failed += keywords_insert("SQL_INTERVAL_MINUTE_TO_SECOND", SQL_INTERVAL_MINUTE_TO_SECOND);
     627         357 :         failed += keywords_insert("SQL_INTERVAL_MONTH", SQL_INTERVAL_MONTH);
     628         357 :         failed += keywords_insert("SQL_INTERVAL_SECOND", SQL_INTERVAL_SECOND);
     629         357 :         failed += keywords_insert("SQL_INTERVAL_YEAR", SQL_INTERVAL_YEAR);
     630         357 :         failed += keywords_insert("SQL_INTERVAL_YEAR_TO_MONTH", SQL_INTERVAL_YEAR_TO_MONTH);
     631         357 :         failed += keywords_insert("SQL_LONGVARBINARY", SQL_LONGVARBINARY);
     632         357 :         failed += keywords_insert("SQL_LONGVARCHAR", SQL_LONGVARCHAR);
     633         357 :         failed += keywords_insert("SQL_NUMERIC", SQL_NUMERIC);
     634         357 :         failed += keywords_insert("SQL_REAL", SQL_REAL);
     635         357 :         failed += keywords_insert("SQL_SMALLINT", SQL_SMALLINT);
     636         357 :         failed += keywords_insert("SQL_TIME", SQL_TIME);
     637         357 :         failed += keywords_insert("SQL_TIMESTAMP", SQL_TIMESTAMP);
     638         357 :         failed += keywords_insert("SQL_TINYINT", SQL_TINYINT);
     639         357 :         failed += keywords_insert("SQL_VARBINARY", SQL_VARBINARY);
     640         357 :         failed += keywords_insert("SQL_VARCHAR", SQL_VARCHAR);
     641         357 :         failed += keywords_insert("SQL_WCHAR", SQL_WCHAR);
     642         357 :         failed += keywords_insert("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR);
     643         357 :         failed += keywords_insert("SQL_WVARCHAR", SQL_WVARCHAR);
     644         357 :         failed += keywords_insert("SQL_TSI_FRAC_SECOND", SQL_TSI_FRAC_SECOND);
     645         357 :         failed += keywords_insert("SQL_TSI_SECOND", SQL_TSI_SECOND);
     646         357 :         failed += keywords_insert("SQL_TSI_MINUTE", SQL_TSI_MINUTE);
     647         357 :         failed += keywords_insert("SQL_TSI_HOUR", SQL_TSI_HOUR);
     648         357 :         failed += keywords_insert("SQL_TSI_DAY", SQL_TSI_DAY);
     649         357 :         failed += keywords_insert("SQL_TSI_WEEK", SQL_TSI_WEEK);
     650         357 :         failed += keywords_insert("SQL_TSI_MONTH", SQL_TSI_MONTH);
     651         357 :         failed += keywords_insert("SQL_TSI_QUARTER", SQL_TSI_QUARTER);
     652         357 :         failed += keywords_insert("SQL_TSI_YEAR", SQL_TSI_YEAR);
     653             : 
     654         357 :         failed += keywords_insert("LEAST", MARGFUNC);
     655         357 :         failed += keywords_insert("GREATEST", MARGFUNC);
     656         357 :         return failed;
     657             : }
     658             : 
     659             : #define find_keyword_bs(lc, s) find_keyword(lc->rs->buf+lc->rs->pos+s)
     660             : 
     661             : void
     662      251986 : scanner_init(struct scanner *s, bstream *rs, stream *ws)
     663             : {
     664      503972 :         *s = (struct scanner) {
     665             :                 .rs = rs,
     666             :                 .ws = ws,
     667             :                 .mode = LINE_N,
     668      251986 :                 .raw_string_mode = GDKgetenv_istrue("raw_strings"),
     669             :                 .aborted = false,
     670             :         };
     671      251986 : }
     672             : 
     673             : void
     674     1398086 : scanner_query_processed(struct scanner *s)
     675             : {
     676     1398086 :         int cur;
     677             : 
     678     1398086 :         if (s->yybak) {
     679      520612 :                 s->rs->buf[s->rs->pos + s->yycur] = s->yybak;
     680      520612 :                 s->yybak = 0;
     681             :         }
     682     1398086 :         if (s->rs) {
     683     1398086 :                 s->rs->pos += s->yycur;
     684             :                 /* completely eat the query including white space after the ; */
     685     2564596 :                 while (s->rs->pos < s->rs->len &&
     686     2161110 :                            (cur = s->rs->buf[s->rs->pos], iswspace(cur))) {
     687     1166510 :                         s->rs->pos++;
     688             :                 }
     689             :         }
     690             :         /*assert(s->rs->pos <= s->rs->len);*/
     691     1398086 :         s->yycur = 0;
     692     1398086 :         s->started = 0;
     693     1398086 :         s->as = 0;
     694     1398086 :         s->schema = NULL;
     695     1398086 : }
     696             : 
     697             : static int
     698          33 : scanner_error(mvc *lc, int cur)
     699             : {
     700          33 :         switch (cur) {
     701           0 :         case EOF:
     702           0 :                 (void) sql_error(lc, 1, SQLSTATE(42000) "Unexpected end of input");
     703           0 :                 return EOF;
     704          33 :         default:
     705             :                 /* on Windows at least, iswcntrl returns TRUE for
     706             :                  * U+FEFF, but we just want consistent error
     707             :                  * messages */
     708          33 :                 (void) sql_error(lc, 1, SQLSTATE(42000) "Unexpected%s character (U+%04X)", iswcntrl(cur) && cur != 0xFEFF ? " control" : "", (unsigned) cur);
     709             :         }
     710          33 :         return LEX_ERROR;
     711             : }
     712             : 
     713             : 
     714             : /*
     715             :    UTF-8 encoding is as follows:
     716             : U-00000000 - U-0000007F: 0xxxxxxx
     717             : U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
     718             : U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
     719             : U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
     720             : U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     721             : U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
     722             : */
     723             : /* To be correctly coded UTF-8, the sequence should be the shortest
     724             :    possible encoding of the value being encoded.  This means that for
     725             :    an encoding of length n+1 (1 <= n <= 5), at least one of the bits in
     726             :    utf8chkmsk[n] should be non-zero (else the encoding could be
     727             :    shorter).
     728             : */
     729             : static const int utf8chkmsk[] = {
     730             :         0x0000007f,
     731             :         0x00000780,
     732             :         0x0000f800,
     733             :         0x001f0000,
     734             :         0x03e00000,
     735             :         0x7c000000
     736             : };
     737             : 
     738             : static void
     739    32682091 : utf8_putchar(struct scanner *lc, int ch)
     740             : {
     741    32682091 :         if ((ch) < 0x80) {
     742    32682086 :                 lc->yycur--;
     743           5 :         } else if ((ch) < 0x800) {
     744           0 :                 lc->yycur -= 2;
     745           5 :         } else if ((ch) < 0x10000) {
     746           5 :                 lc->yycur -= 3;
     747             :         } else {
     748           0 :                 lc->yycur -= 4;
     749             :         }
     750    32682091 : }
     751             : 
     752             : static inline int
     753   142242748 : scanner_read_more(struct scanner *lc, size_t n)
     754             : {
     755   142242748 :         bstream *b = lc->rs;
     756   142242748 :         bool more = false;
     757             : 
     758             : 
     759   142242748 :         if (lc->aborted)
     760             :                 return EOF;
     761   142246341 :         while (b->len < b->pos + lc->yycur + n) {
     762             : 
     763      138734 :                 if (lc->mode == LINE_1 || !lc->started)
     764             :                         return EOF;
     765             : 
     766             :                 /* query is not finished ask for more */
     767        6203 :                 if (b->eof || !isa_block_stream(b->s)) {
     768        4403 :                         if (bstream_getoob(b)) {
     769           0 :                                 lc->aborted = true;
     770           0 :                                 return EOF;
     771             :                         }
     772        1800 :                         if (mnstr_write(lc->ws, PROMPT2, sizeof(PROMPT2) - 1, 1) == 1)
     773        1800 :                                 mnstr_flush(lc->ws, MNSTR_FLUSH_DATA);
     774        1800 :                         b->eof = false;
     775        1800 :                         more = true;
     776             :                 }
     777             :                 /* we need more query text */
     778        3600 :                 if (bstream_next(b) < 0) {
     779           0 :                         if (mnstr_errnr(b->s) == MNSTR_INTERRUPT) {
     780             :                                 // now what?
     781           0 :                                 lc->errstr = "Query aborted";
     782           0 :                                 lc->aborted = true;
     783           0 :                                 mnstr_clearerr(b->s);
     784             :                         }
     785           0 :                         return EOF;
     786        3600 :                 } else if (/* we asked for more data but didn't get any */
     787        1800 :                            (more && b->eof && b->len < b->pos + lc->yycur + n))
     788             :                         return EOF;
     789        3593 :                 if (more && b->pos + lc->yycur + 2 == b->len && b->buf[b->pos + lc->yycur] == '\200' && b->buf[b->pos + lc->yycur + 1] == '\n') {
     790           0 :                         lc->errstr = "Query aborted";
     791           0 :                         b->len -= 2;
     792           0 :                         b->buf[b->len] = 0;
     793           0 :                         return EOF;
     794             :                 }
     795             :         }
     796             :         return 1;
     797             : }
     798             : 
     799             : static inline int
     800   140957503 : scanner_getc(struct scanner *lc)
     801             : {
     802   140957503 :         bstream *b = lc->rs;
     803   140957503 :         unsigned char *s = NULL;
     804   140957503 :         int c, m, n, mask;
     805             : 
     806   140957503 :         if (scanner_read_more(lc, 1) == EOF) {
     807             :                 //lc->errstr = SQLSTATE(42000) "end of input stream";
     808             :                 return EOF;
     809             :         }
     810   140824567 :         lc->errstr = NULL;
     811             : 
     812   140824567 :         s = (unsigned char *) b->buf + b->pos + lc->yycur++;
     813   140824567 :         if (((c = *s) & 0x80) == 0) {
     814             :                 /* 7-bit char */
     815             :                 return c;
     816             :         }
     817       88250 :         for (n = 0, m = 0x40; c & m; n++, m >>= 1)
     818             :                 ;
     819             :         /* n now is number of 10xxxxxx bytes that should follow */
     820       29443 :         if (n == 0 || n >= 6 || (b->pos + n) > b->len) {
     821             :                 /* incorrect UTF-8 sequence */
     822             :                 /* n==0: c == 10xxxxxx */
     823             :                 /* n>=6: c == 1111111x */
     824           0 :                 lc->errstr = SQLSTATE(42000) "invalid start of UTF-8 sequence";
     825           0 :                 goto error;
     826             :         }
     827             : 
     828       29443 :         if (scanner_read_more(lc, (size_t) n) == EOF)
     829             :                 return EOF;
     830       29443 :         s = (unsigned char *) b->buf + b->pos + lc->yycur;
     831             : 
     832       29443 :         mask = utf8chkmsk[n];
     833       29443 :         c &= ~(0xFFC0 >> n);  /* remove non-x bits */
     834       88249 :         while (--n >= 0) {
     835       58807 :                 c <<= 6;
     836       58807 :                 lc->yycur++;
     837       58807 :                 if (((m = *s++) & 0xC0) != 0x80) {
     838             :                         /* incorrect UTF-8 sequence: byte is not 10xxxxxx */
     839             :                         /* this includes end-of-string (m == 0) */
     840           1 :                         lc->errstr = SQLSTATE(42000) "invalid continuation in UTF-8 sequence";
     841           1 :                         goto error;
     842             :                 }
     843       58806 :                 c |= m & 0x3F;
     844             :         }
     845       29442 :         if ((c & mask) == 0) {
     846             :                 /* incorrect UTF-8 sequence: not shortest possible */
     847           0 :                 lc->errstr = SQLSTATE(42000) "not shortest possible UTF-8 sequence";
     848           0 :                 goto error;
     849             :         }
     850             : 
     851             :         return c;
     852             : 
     853           1 : error:
     854           1 :         if (b->pos + lc->yycur < b->len)    /* skip bogus char */
     855           0 :                 lc->yycur++;
     856             :         return EOF;
     857             : }
     858             : 
     859             : static int
     860    29201293 : scanner_token(struct scanner *lc, int token)
     861             : {
     862    29201293 :         lc->yybak = lc->rs->buf[lc->rs->pos + lc->yycur];
     863    29201293 :         lc->rs->buf[lc->rs->pos + lc->yycur] = 0;
     864    29201293 :         lc->yyval = token;
     865    29201293 :         return lc->yyval;
     866             : }
     867             : 
     868             : static int
     869     2160781 : scanner_string(mvc *c, int quote, bool escapes)
     870             : {
     871     2160781 :         struct scanner *lc = &c->scanner;
     872     2160781 :         bstream *rs = lc->rs;
     873     2160781 :         int cur = quote;
     874     2160781 :         bool escape = false;
     875     2160781 :         const size_t limit = quote == '"' ? 1 << 11 : 1 << 30;
     876             : 
     877     2160781 :         lc->started = 1;
     878     2198929 :         while (cur != EOF) {
     879     2198914 :                 size_t pos = 0;
     880     2198914 :                 const size_t yycur = rs->pos + lc->yycur;
     881             : 
     882    35747924 :                 while (cur != EOF && (quote != '"' || cur != 0xFEFF) && pos < limit &&
     883    33549010 :                        (((cur = rs->buf[yycur + pos++]) & 0x80) == 0) &&
     884    67068566 :                        cur && (cur != quote || escape)) {
     885    31350097 :                         if (escapes && cur == '\\')
     886        6840 :                                 escape = !escape;
     887             :                         else
     888             :                                 escape = false;
     889             :                 }
     890     2198914 :                 if (pos == limit) {
     891           0 :                         (void) sql_error(c, 2, SQLSTATE(42000) "string too long");
     892           0 :                         return LEX_ERROR;
     893             :                 }
     894             :                 /* BOM character not allowed as an identifier */
     895     2198914 :                 if (cur == EOF || (quote == '"' && cur == 0xFEFF))
     896           1 :                         return scanner_error(c, cur);
     897     2198913 :                 lc->yycur += pos;
     898             :                 /* check for quote escaped quote: Obscure SQL Rule */
     899     2198913 :                 if (cur == quote && rs->buf[yycur + pos] == quote) {
     900        8707 :                         lc->yycur++;
     901        8707 :                         continue;
     902             :                 }
     903     2190206 :                 assert(yycur + pos <= rs->len + 1);
     904     2190206 :                 if (cur == quote && !escape) {
     905     2160751 :                         return scanner_token(lc, STRING);
     906             :                 }
     907       29455 :                 lc->yycur--; /* go back to current (possibly invalid) char */
     908             :                 /* long utf8, if correct isn't the quote */
     909       29455 :                 if (!cur) {
     910          30 :                         if (lc->rs->len >= lc->rs->pos + lc->yycur + 1) {
     911          14 :                                 (void) sql_error(c, 2, SQLSTATE(42000) "NULL byte in string");
     912          14 :                                 return LEX_ERROR;
     913             :                         }
     914          16 :                         cur = scanner_read_more(lc, 1);
     915             :                 } else {
     916       29425 :                         cur = scanner_getc(lc);
     917             :                 }
     918             :         }
     919          15 :         (void) sql_error(c, 2, "%s", lc->errstr ? lc->errstr : SQLSTATE(42000) "Unexpected end of input");
     920          15 :         return EOF;
     921             : }
     922             : 
     923             : /* scan a structure {blah} into a string. We only count the matching {}
     924             :  * unless escaped. We do not consider embeddings in string literals yet
     925             :  */
     926             : 
     927             : static int
     928         234 : scanner_body(mvc *c)
     929             : {
     930         234 :         struct scanner *lc = &c->scanner;
     931         234 :         bstream *rs = lc->rs;
     932         234 :         int cur = (int) 'x';
     933         234 :         int blk = 1;
     934         234 :         bool escape = false;
     935             : 
     936         234 :         lc->started = 1;
     937         234 :         assert(rs->buf[rs->pos + lc->yycur-1] == '{');
     938         290 :         while (cur != EOF) {
     939         290 :                 size_t pos = rs->pos + lc->yycur;
     940             : 
     941       32350 :                 while ((((cur = rs->buf[pos++]) & 0x80) == 0) && cur && (blk || escape)) {
     942       32060 :                         if (cur != '\\')
     943             :                                 escape = false;
     944             :                         else
     945          12 :                                 escape = !escape;
     946       32060 :                         blk += cur =='{';
     947       32060 :                         blk -= cur =='}';
     948             :                 }
     949         290 :                 lc->yycur = pos - rs->pos;
     950         290 :                 assert(pos <= rs->len + 1);
     951         290 :                 if (blk == 0 && !escape){
     952         234 :                         lc->yycur--; /* go back to current (possibly invalid) char */
     953         234 :                         return scanner_token(lc, X_BODY);
     954             :                 }
     955          56 :                 lc->yycur--; /* go back to current (possibly invalid) char */
     956          56 :                 if (!cur) {
     957          56 :                         if (lc->rs->len >= lc->rs->pos + lc->yycur + 1) {
     958           0 :                                 (void) sql_error(c, 2, SQLSTATE(42000) "NULL byte in string");
     959           0 :                                 return LEX_ERROR;
     960             :                         }
     961          56 :                         cur = scanner_read_more(lc, 1);
     962             :                 } else {
     963           0 :                         cur = scanner_getc(lc);
     964             :                 }
     965             :         }
     966           0 :         (void) sql_error(c, 2, SQLSTATE(42000) "Unexpected end of input");
     967           0 :         return EOF;
     968             : }
     969             : 
     970             : static int
     971    14019080 : keyword_or_ident(mvc * c, int cur)
     972             : {
     973    14019080 :         struct scanner *lc = &c->scanner;
     974    14019080 :         keyword *k = NULL;
     975    14019080 :         size_t s;
     976             : 
     977    14019080 :         lc->started = 1;
     978    14019080 :         utf8_putchar(lc, cur);
     979    14019085 :         s = lc->yycur;
     980    14019085 :         lc->yyval = IDENT;
     981    84194319 :         while ((cur = scanner_getc(lc)) != EOF) {
     982    84194216 :                 if (!iswalnum(cur) && cur != '_') {
     983    14018982 :                         utf8_putchar(lc, cur);
     984    14018978 :                         (void)scanner_token(lc, IDENT);
     985    14018978 :                         if ((k = find_keyword_bs(lc,s)))
     986     8575579 :                                 lc->yyval = k->token;
     987    14019091 :                         return lc->yyval;
     988             :                 }
     989             :         }
     990             :         if (cur < 0)
     991             :                 return cur;
     992             :         (void)scanner_token(lc, IDENT);
     993             :         if ((k = find_keyword_bs(lc,s)))
     994             :                 lc->yyval = k->token;
     995             :         return lc->yyval;
     996             : }
     997             : 
     998             : static int
     999    14582163 : skip_white_space(struct scanner * lc)
    1000             : {
    1001    18228006 :         int cur;
    1002             : 
    1003    18228006 :         do {
    1004    18228006 :                 lc->yysval = lc->yycur;
    1005    18228006 :         } while ((cur = scanner_getc(lc)) != EOF && iswspace(cur));
    1006    14582364 :         return cur;
    1007             : }
    1008             : 
    1009             : static int
    1010       71222 : skip_c_comment(struct scanner * lc)
    1011             : {
    1012       71222 :         int cur;
    1013       71222 :         int prev = 0;
    1014       71222 :         int started = lc->started;
    1015       71222 :         int depth = 1;
    1016             : 
    1017       71222 :         lc->started = 1;
    1018     1436228 :         while (depth > 0 && (cur = scanner_getc(lc)) != EOF) {
    1019     1365006 :                 if (prev == '*' && cur == '/')
    1020       71222 :                         depth--;
    1021     1293784 :                 else if (prev == '/' && cur == '*') {
    1022             :                         /* block comments can nest */
    1023           0 :                         cur = 0; /* prevent slash-star-slash from matching */
    1024           0 :                         depth++;
    1025             :                 }
    1026             :                 prev = cur;
    1027             :         }
    1028       71222 :         lc->yysval = lc->yycur;
    1029       71222 :         lc->started = started;
    1030             :         /* a comment is equivalent to a newline */
    1031       71222 :         return cur == EOF ? cur : '\n';
    1032             : }
    1033             : 
    1034             : static int
    1035        3273 : skip_sql_comment(struct scanner * lc)
    1036             : {
    1037        3273 :         int cur;
    1038        3273 :         int started = lc->started;
    1039             : 
    1040        3273 :         lc->started = 1;
    1041      833837 :         while ((cur = scanner_getc(lc)) != EOF && (cur != '\n'))
    1042             :                 ;
    1043        3273 :         lc->yysval = lc->yycur;
    1044        3273 :         lc->started = started;
    1045             :         /* a comment is equivalent to a newline */
    1046        3273 :         return cur;
    1047             : }
    1048             : 
    1049             : static int tokenize(mvc * lc, int cur);
    1050             : 
    1051     5949016 : static inline bool is_valid_decimal_digit(int cur) { return (iswdigit(cur)); }
    1052          13 : static inline bool is_valid_binary_digit(int cur) { return (iswdigit(cur) && cur < '2'); }
    1053          10 : static inline bool is_valid_octal_digit(int cur) { return (iswdigit(cur) && cur < '8'); }
    1054        3688 : static inline bool is_valid_hexadecimal_digit(int cur) { return iswxdigit(cur); }
    1055             : 
    1056     1969812 : static inline int check_validity_number(mvc* c, int pcur, bool initial_underscore_allowed, int *token, int type) {
    1057     1969812 :         struct scanner *lc = &c->scanner;
    1058     1969812 :         bool (*is_valid_n_ary_digit)(int);
    1059             : 
    1060     1969812 :         if (pcur == '_' && !initial_underscore_allowed)  /* ERROR: initial underscore not allowed */  {
    1061           0 :                 *token = 0;
    1062           0 :                 return '_';
    1063             :         }
    1064             : 
    1065     1969812 :         switch (type) {
    1066             :         case BINARYNUM:
    1067             :                 is_valid_n_ary_digit = &is_valid_binary_digit;
    1068             :                 break;
    1069           3 :         case OCTALNUM:
    1070           3 :                 is_valid_n_ary_digit = &is_valid_octal_digit;
    1071           3 :                 break;
    1072         280 :         case HEXADECIMALNUM:
    1073         280 :                 is_valid_n_ary_digit = &is_valid_hexadecimal_digit;
    1074         280 :                 break;
    1075     1969527 :         default:
    1076     1969527 :                 is_valid_n_ary_digit = &is_valid_decimal_digit;
    1077     1969527 :                 break;
    1078             :         }
    1079             : 
    1080     1969812 :         if ( !(pcur == '_' || is_valid_n_ary_digit(pcur)) ) /* ERROR: first digit is not valid */ {
    1081          18 :                 *token = 0;
    1082          18 :                 return pcur;
    1083             :         }
    1084             : 
    1085     1969646 :         int cur = scanner_getc(lc);
    1086     1969560 :         *token = type;
    1087     3984959 :         while (cur != EOF) {
    1088     3984970 :                 if (cur == '_') {
    1089          25 :                         if (pcur == '_') /* ERROR: multiple consecutive underscores */ {
    1090           2 :                                 *token = 0;
    1091           2 :                                 return '_';
    1092             :                         }
    1093             :                 }
    1094     3984945 :                 else if (!is_valid_n_ary_digit(cur))
    1095             :                         break;
    1096     2015558 :                 pcur = cur;
    1097     2015558 :                 cur = scanner_getc(lc);
    1098             :         }
    1099             : 
    1100     1969261 :         if (pcur == '_')  {
    1101           3 :                 *token = 0;
    1102           3 :                 if (iswalnum(cur))       /* ERROR: not a valid digit */
    1103             :                         return cur;
    1104             :                 else                            /* ERROR: number ends with underscore */
    1105             :                         return '_';
    1106             :         }
    1107             : 
    1108             :         return cur;
    1109             : }
    1110             : 
    1111             : static int
    1112     1956430 : number(mvc * c, int cur)
    1113             : {
    1114     1956430 :         struct scanner *lc = &c->scanner;
    1115     1956430 :         int token = sqlINT;
    1116             : 
    1117             :         /* a number has one of these forms (expressed in regular expressions):
    1118             :          * 0x[0-9A-Fa-f]+                   -- (hexadecimal) INTEGER
    1119             :          * \.[0-9]+                         -- DECIMAL
    1120             :          * [0-9]+\.[0-9]*                   -- DECIMAL
    1121             :          * [0-9]+@0                         -- OID
    1122             :          * [0-9]*\.[0-9]+[eE][-+]?[0-9]+    -- REAL
    1123             :          * [0-9]+(\.[0-9]*)?[eE][-+]?[0-9]+ -- REAL
    1124             :          * [0-9]+                           -- (decimal) INTEGER
    1125             :          */
    1126     1956430 :         lc->started = 1;
    1127     1956430 :         if (cur == '0') {
    1128      317956 :                 switch ((cur = scanner_getc(lc))) {
    1129           2 :                 case 'b':
    1130           2 :                         cur = scanner_getc(lc);
    1131           2 :                         if ((cur = check_validity_number(c, cur, true, &token, BINARYNUM)) == EOF) return cur;
    1132             :                         break;
    1133           3 :                 case 'o':
    1134           3 :                         cur = scanner_getc(lc);
    1135           3 :                         if ((cur = check_validity_number(c,  cur, true, &token, OCTALNUM)) == EOF) return cur;
    1136             :                         break;
    1137         280 :                 case 'x':
    1138         280 :                         cur = scanner_getc(lc);
    1139         280 :                         if ((cur = check_validity_number(c,  cur, true, &token, HEXADECIMALNUM)) == EOF) return cur;
    1140             :                         break;
    1141      317669 :                 default:
    1142      317669 :                         utf8_putchar(lc, cur);
    1143      317669 :                         cur = '0';
    1144             :                 }
    1145             :         }
    1146     1956425 :         if (token == sqlINT) {
    1147     1956125 :                 if ((cur = check_validity_number(c, cur, false, &token, sqlINT)) == EOF) return cur;
    1148     1955595 :                 if (cur == '@') {
    1149           0 :                         if (token == sqlINT) {
    1150           0 :                                 cur = scanner_getc(lc);
    1151           0 :                                 if (cur == EOF)
    1152             :                                         return cur;
    1153           0 :                                 if (cur == '0') {
    1154           0 :                                         cur = scanner_getc(lc);
    1155           0 :                                         if (cur == EOF)
    1156             :                                                 return cur;
    1157           0 :                                         token = OIDNUM;
    1158             :                                 } else {
    1159             :                                         /* number + '@' not followed by 0: show '@' as erroneous */
    1160           0 :                                         utf8_putchar(lc, cur);
    1161           0 :                                         cur = '@';
    1162           0 :                                         token = 0;
    1163             :                                 }
    1164             :                         }
    1165             :                 } else {
    1166     1955595 :                         if (cur == '.') {
    1167       11188 :                                 cur = scanner_getc(lc);
    1168       11188 :                                 if (iswalnum(cur)) /* early exit for numerical forms with final . e.g. 10. */
    1169       11181 :                                 if ((cur = check_validity_number(c, cur, false, &token, INTNUM)) == EOF) return cur;
    1170             :                         }
    1171     1955595 :                         if (token != 0)
    1172     1955601 :                         if (cur == 'e' || cur == 'E') {
    1173        2231 :                                 cur = scanner_getc(lc);
    1174        2231 :                                 if (cur == '+' || cur == '-')
    1175        2111 :                                         cur = scanner_getc(lc);
    1176        2231 :                                 if ((cur = check_validity_number(c, cur, false, &token, APPROXNUM)) == EOF) return cur;
    1177             :                         }
    1178             :                 }
    1179             :         }
    1180             : 
    1181     1953664 :         assert(cur != EOF);
    1182             : 
    1183     1955895 :         if (iswalnum(cur)) /* ERROR: not a valid digit */
    1184           6 :                 token = 0;
    1185             : 
    1186     1955895 :         utf8_putchar(lc, cur);
    1187             : 
    1188     1955853 :         if (token) {
    1189     1955843 :                 return scanner_token(lc, token);
    1190             :         } else {
    1191          10 :                 (void)sql_error( c, 2, SQLSTATE(42000) "Unexpected symbol %lc", (wint_t) cur);
    1192          10 :                 return LEX_ERROR;
    1193             :         }
    1194             : }
    1195             : 
    1196             : static
    1197    13293798 : int scanner_symbol(mvc * c, int cur)
    1198             : {
    1199    13293798 :         struct scanner *lc = &c->scanner;
    1200    13293798 :         int next = 0;
    1201    13293798 :         int started = lc->started;
    1202             : 
    1203    13293798 :         switch (cur) {
    1204       73884 :         case '/':
    1205       73884 :                 lc->started = 1;
    1206       73884 :                 next = scanner_getc(lc);
    1207       73884 :                 if (next < 0)
    1208             :                         return EOF;
    1209       73884 :                 if (next == '*') {
    1210       71222 :                         lc->started = started;
    1211       71222 :                         cur = skip_c_comment(lc);
    1212       71222 :                         if (cur < 0)
    1213             :                                 return EOF;
    1214       71222 :                         return tokenize(c, cur);
    1215             :                 } else {
    1216        2662 :                         utf8_putchar(lc, next);
    1217        2662 :                         return scanner_token(lc, cur);
    1218             :                 }
    1219           0 :         case '0':
    1220             :         case '1':
    1221             :         case '2':
    1222             :         case '3':
    1223             :         case '4':
    1224             :         case '5':
    1225             :         case '6':
    1226             :         case '7':
    1227             :         case '8':
    1228             :         case '9':
    1229           0 :                 return number(c, cur);
    1230           8 :         case '#':
    1231           8 :                 if ((cur = skip_sql_comment(lc)) == EOF)
    1232             :                         return cur;
    1233           8 :                 return tokenize(c, cur);
    1234      823405 :         case '\'':
    1235      823405 :                 if (lc->raw_string_mode || lc->next_string_is_raw)
    1236          50 :                         return scanner_string(c, cur, false);
    1237      823355 :                 return scanner_string(c, cur, true);
    1238     1330151 :         case '"':
    1239     1330151 :                 return scanner_string(c, cur, false);
    1240         500 :         case '{':
    1241             :                 // if previous tokens like LANGUAGE IDENT
    1242             :                 // TODO checking on IDENT only may not be enough
    1243         500 :                 if (lc->yylast == IDENT)
    1244         234 :                         return scanner_body(c);
    1245         266 :                 lc->started = 1;
    1246         266 :                 return scanner_token(lc, cur);
    1247         266 :         case '}':
    1248         266 :                 lc->started = 1;
    1249         266 :                 return scanner_token(lc, cur);
    1250       30599 :         case '-':
    1251       30599 :                 lc->started = 1;
    1252       30599 :                 next = scanner_getc(lc);
    1253       30599 :                 if (next < 0)
    1254             :                         return EOF;
    1255       30598 :                 if (next == '-') {
    1256        3265 :                         lc->started = started;
    1257        3265 :                         if ((cur = skip_sql_comment(lc)) == EOF)
    1258             :                                 return cur;
    1259        3265 :                         return tokenize(c, cur);
    1260             :                 }
    1261       27333 :                 lc->started = 1;
    1262       27333 :                 utf8_putchar(lc, next);
    1263       27333 :                 return scanner_token(lc, cur);
    1264          12 :         case '~': /* binary not */
    1265          12 :                 lc->started = 1;
    1266          12 :                 next = scanner_getc(lc);
    1267          12 :                 if (next < 0)
    1268             :                         return EOF;
    1269          12 :                 if (next == '=')
    1270           5 :                         return scanner_token(lc, GEOM_MBR_EQUAL);
    1271           7 :                 utf8_putchar(lc, next);
    1272           7 :                 return scanner_token(lc, cur);
    1273     7419115 :         case '^': /* binary xor */
    1274             :         case '*':
    1275             :         case '?':
    1276             :         case ':':
    1277             :         case '%':
    1278             :         case '+':
    1279             :         case '(':
    1280             :         case ')':
    1281             :         case ',':
    1282             :         case '=':
    1283             :         case '[':
    1284             :         case ']':
    1285     7419115 :                 lc->started = 1;
    1286     7419115 :                 return scanner_token(lc, cur);
    1287        6397 :         case '&':
    1288        6397 :                 lc->started = 1;
    1289        6397 :                 cur = scanner_getc(lc);
    1290        6397 :                 if (cur < 0)
    1291             :                         return EOF;
    1292        6397 :                 if (cur < 0)
    1293             :                         return EOF;
    1294        6397 :                 if(cur == '<') {
    1295           3 :                         next = scanner_getc(lc);
    1296           3 :                         if (next < 0)
    1297             :                                 return EOF;
    1298           3 :                         if(next == '|') {
    1299           0 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_BELOW);
    1300             :                         } else {
    1301           3 :                                 utf8_putchar(lc, next); //put the char back
    1302           3 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_LEFT);
    1303             :                         }
    1304        6394 :                 } else if(cur == '>')
    1305           3 :                         return scanner_token(lc, GEOM_OVERLAP_OR_RIGHT);
    1306        6391 :                 else if(cur == '&')
    1307           3 :                         return scanner_token(lc, GEOM_OVERLAP);
    1308             :                 else {/* binary and */
    1309        6388 :                         utf8_putchar(lc, cur); //put the char back
    1310        6388 :                         return scanner_token(lc, '&');
    1311             :                 }
    1312          19 :         case '@':
    1313          19 :                 lc->started = 1;
    1314          19 :                 return scanner_token(lc, AT);
    1315     1043618 :         case ';':
    1316     1043618 :                 lc->started = 0;
    1317     1043618 :                 return scanner_token(lc, SCOLON);
    1318          35 :         case '!':
    1319          35 :                 lc->started = 1;
    1320          35 :                 cur = scanner_getc(lc);
    1321          35 :                 if (cur < 0)
    1322             :                         return EOF;
    1323          35 :                 else if (cur == '=') {
    1324          29 :                         lc->rs->buf[lc->rs->pos + lc->yycur - 2] = '<';
    1325          29 :                         lc->rs->buf[lc->rs->pos + lc->yycur - 1] = '>';
    1326          29 :                         return scanner_token( lc, COMPARISON);
    1327             :                 } else {
    1328           6 :                         utf8_putchar(lc, cur); //put the char back
    1329             :                 }
    1330           6 :                 return scanner_token(lc, '!');
    1331       52805 :         case '<':
    1332       52805 :                 lc->started = 1;
    1333       52805 :                 cur = scanner_getc(lc);
    1334       52805 :                 if (cur < 0)
    1335             :                         return EOF;
    1336       52805 :                 if (cur == '=') {
    1337        3140 :                         return scanner_token( lc, COMPARISON);
    1338       49665 :                 } else if (cur == '>') {
    1339       35940 :                         return scanner_token( lc, COMPARISON);
    1340       13725 :                 } else if (cur == '<') {
    1341          44 :                         next = scanner_getc(lc);
    1342          44 :                         if (next < 0)
    1343             :                                 return EOF;
    1344          44 :                         if (next == '=') {
    1345           4 :                                 return scanner_token( lc, LEFT_SHIFT_ASSIGN);
    1346          40 :                         } else if (next == '|') {
    1347           1 :                                 return scanner_token(lc, GEOM_BELOW);
    1348             :                         } else {
    1349          39 :                                 utf8_putchar(lc, next); //put the char back
    1350          39 :                                 return scanner_token( lc, LEFT_SHIFT);
    1351             :                         }
    1352       13681 :                 } else if(cur == '-') {
    1353          19 :                         next = scanner_getc(lc);
    1354          19 :                         if (next < 0)
    1355             :                                 return EOF;
    1356          19 :                         if(next == '>') {
    1357           7 :                                 return scanner_token(lc, GEOM_DIST);
    1358             :                         } else {
    1359             :                                 //put the characters back and fall in the next possible case
    1360          12 :                                 utf8_putchar(lc, next);
    1361          12 :                                 utf8_putchar(lc, cur);
    1362          12 :                                 return scanner_token( lc, COMPARISON);
    1363             :                         }
    1364             :                 } else {
    1365       13662 :                         utf8_putchar(lc, cur);
    1366       13662 :                         return scanner_token( lc, COMPARISON);
    1367             :                 }
    1368       47895 :         case '>':
    1369       47895 :                 lc->started = 1;
    1370       47895 :                 cur = scanner_getc(lc);
    1371       47895 :                 if (cur < 0)
    1372             :                         return EOF;
    1373       47895 :                 if (cur == '>') {
    1374        2713 :                         cur = scanner_getc(lc);
    1375        2713 :                         if (cur < 0)
    1376             :                                 return EOF;
    1377        2713 :                         if (cur == '=')
    1378           3 :                                 return scanner_token( lc, RIGHT_SHIFT_ASSIGN);
    1379        2710 :                         utf8_putchar(lc, cur);
    1380        2710 :                         return scanner_token( lc, RIGHT_SHIFT);
    1381       45182 :                 } else if (cur != '=') {
    1382       42912 :                         utf8_putchar(lc, cur);
    1383       42912 :                         return scanner_token( lc, COMPARISON);
    1384             :                 } else {
    1385        2270 :                         return scanner_token( lc, COMPARISON);
    1386             :                 }
    1387     2276140 :         case '.':
    1388     2276140 :                 lc->started = 1;
    1389     2276140 :                 cur = scanner_getc(lc);
    1390     2276140 :                 if (cur < 0)
    1391             :                         return EOF;
    1392     2276139 :                 if (!iswdigit(cur)) {
    1393     2276125 :                         utf8_putchar(lc, cur);
    1394     2276125 :                         return scanner_token( lc, '.');
    1395             :                 } else {
    1396          14 :                         utf8_putchar(lc, cur);
    1397          14 :                         cur = '.';
    1398          14 :                         return number(c, cur);
    1399             :                 }
    1400      188939 :         case '|': /* binary or or string concat */
    1401      188939 :                 lc->started = 1;
    1402      188939 :                 cur = scanner_getc(lc);
    1403      188939 :                 if (cur < 0)
    1404             :                         return EOF;
    1405      188939 :                 if (cur == '|') {
    1406      188914 :                         return scanner_token(lc, CONCATSTRING);
    1407          25 :                 } else if (cur == '&') {
    1408           0 :                         next = scanner_getc(lc);
    1409           0 :                         if (next < 0)
    1410             :                                 return EOF;
    1411           0 :                         if(next == '>') {
    1412           0 :                                 return scanner_token(lc, GEOM_OVERLAP_OR_ABOVE);
    1413             :                         } else {
    1414           0 :                                 utf8_putchar(lc, next); //put the char back
    1415           0 :                                 utf8_putchar(lc, cur); //put the char back
    1416           0 :                                 return scanner_token(lc, '|');
    1417             :                         }
    1418          25 :                 } else if (cur == '>') {
    1419           1 :                         next = scanner_getc(lc);
    1420           1 :                         if (next < 0)
    1421             :                                 return EOF;
    1422           1 :                         if(next == '>') {
    1423           1 :                                 return scanner_token(lc, GEOM_ABOVE);
    1424             :                         } else {
    1425           0 :                                 utf8_putchar(lc, next); //put the char back
    1426           0 :                                 utf8_putchar(lc, cur); //put the char back
    1427           0 :                                 return scanner_token(lc, '|');
    1428             :                         }
    1429             :                 } else {
    1430          24 :                         utf8_putchar(lc, cur);
    1431          24 :                         return scanner_token(lc, '|');
    1432             :                 }
    1433             :         }
    1434          10 :         (void)sql_error( c, 3, SQLSTATE(42000) "Unexpected symbol (%lc)", (wint_t) cur);
    1435          10 :         return LEX_ERROR;
    1436             : }
    1437             : 
    1438             : static int
    1439    29293182 : tokenize(mvc * c, int cur)
    1440             : {
    1441    29293182 :         struct scanner *lc = &c->scanner;
    1442    58415254 :         while (1) {
    1443    43854218 :                 if (cur == 0xFEFF) {
    1444             :                         /* on Linux at least, iswpunct returns TRUE
    1445             :                          * for U+FEFF, but we don't want that, we just
    1446             :                          * want to go to the scanner_error case
    1447             :                          * below */
    1448             :                         ;
    1449    43854313 :                 } else if (iswspace(cur)) {
    1450    14578015 :                         if ((cur = skip_white_space(lc)) == EOF)
    1451             :                                 return cur;
    1452    14561036 :                         continue;  /* try again */
    1453    29276298 :                 } else if (iswdigit(cur)) {
    1454     1956441 :                         return number(c, cur);
    1455    27319857 :                 } else if (iswalpha(cur) || cur == '_') {
    1456    13989246 :                         switch (cur) {
    1457      666895 :                         case 'e': /* string with escapes */
    1458             :                         case 'E':
    1459      666895 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1460      666895 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '\'') {
    1461        3915 :                                         return scanner_string(c, scanner_getc(lc), true);
    1462             :                                 }
    1463             :                                 break;
    1464      426736 :                         case 'x': /* blob */
    1465             :                         case 'X':
    1466             :                         case 'r': /* raw string */
    1467             :                         case 'R':
    1468      426736 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1469      426736 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '\'') {
    1470        3293 :                                         return scanner_string(c, scanner_getc(lc), false);
    1471             :                                 }
    1472             :                                 break;
    1473      162136 :                         case 'u': /* unicode string */
    1474             :                         case 'U':
    1475      162136 :                                 if (scanner_read_more(lc, 1) != EOF &&
    1476      162153 :                                     lc->rs->buf[lc->rs->pos + lc->yycur] == '&' &&
    1477          17 :                                     scanner_read_more(lc, 2) != EOF &&
    1478          17 :                                     (lc->rs->buf[lc->rs->pos + lc->yycur + 1] == '\'' ||
    1479             :                                      lc->rs->buf[lc->rs->pos + lc->yycur + 1] == '"')) {
    1480          17 :                                         cur = scanner_getc(lc); /* '&' */
    1481          17 :                                         return scanner_string(c, scanner_getc(lc), false);
    1482             :                                 }
    1483             :                                 break;
    1484             :                         default:
    1485             :                                 break;
    1486             :                         }
    1487    14019076 :                         return keyword_or_ident(c, cur);
    1488    13293556 :                 } else if (iswpunct(cur)) {
    1489    13293429 :                         return scanner_symbol(c, cur);
    1490             :                 }
    1491          32 :                 if (cur == EOF) {
    1492           0 :                         if (lc->mode == LINE_1 || !lc->started )
    1493             :                                 return cur;
    1494           0 :                         return scanner_error(c, cur);
    1495             :                 }
    1496             :                 /* none of the above: error */
    1497          32 :                 return scanner_error(c, cur);
    1498             :         }
    1499             : }
    1500             : 
    1501             : /* SQL 'quoted' idents consist of a set of any character of
    1502             :  * the source language character set other than a 'quote'
    1503             :  *
    1504             :  * MonetDB has 3 restrictions:
    1505             :  *      1 we disallow '%' as the first character.
    1506             :  *      2 the length is limited to 1024 characters
    1507             :  *      3 the identifier 'TID%' is not allowed
    1508             :  */
    1509             : static bool
    1510     1330140 : valid_ident(const char *restrict s, char *restrict dst)
    1511             : {
    1512     1330140 :         int p = 0;
    1513             : 
    1514     1330140 :         if (*s == '%')
    1515             :                 return false;
    1516             : 
    1517     9844622 :         while (*s) {
    1518     8514482 :                 if ((dst[p++] = *s++) == '"' && *s == '"')
    1519          68 :                         s++;
    1520     8514482 :                 if (p >= 1024)
    1521             :                         return false;
    1522             :         }
    1523     1330140 :         dst[p] = '\0';
    1524     1330140 :         if (strcmp(dst, TID + 1) == 0) /* an index named 'TID%' could interfere with '%TID%' */
    1525             :                 return false;
    1526             :         return true;
    1527             : }
    1528             : 
    1529             : static inline int
    1530    29688961 : sql_get_next_token(YYSTYPE *yylval, void *parm)
    1531             : {
    1532    29688961 :         mvc *c = (mvc*)parm;
    1533    29688961 :         struct scanner *lc = &c->scanner;
    1534    29688961 :         int token = 0, cur = 0;
    1535             : 
    1536    29688961 :         if (lc->rs->buf == NULL) /* malloc failure */
    1537             :                 return EOF;
    1538             : 
    1539    29688961 :         if (lc->yynext) {
    1540      358073 :                 int next = lc->yynext;
    1541             : 
    1542      358073 :                 lc->yynext = 0;
    1543      358073 :                 return(next);
    1544             :         }
    1545             : 
    1546    29330888 :         if (lc->yybak) {
    1547    28252524 :                 lc->rs->buf[lc->rs->pos + lc->yycur] = lc->yybak;
    1548    28252524 :                 lc->yybak = 0;
    1549             :         }
    1550             : 
    1551    29330888 :         lc->yysval = lc->yycur;
    1552    29330888 :         lc->yylast = lc->yyval;
    1553    29330888 :         cur = scanner_getc(lc);
    1554    29330414 :         if (cur < 0)
    1555             :                 return EOF;
    1556    29219233 :         token = tokenize(c, cur);
    1557             : 
    1558    29220356 :         yylval->sval = (lc->rs->buf + lc->rs->pos + lc->yysval);
    1559             : 
    1560    29220356 :         if (token == KW_TYPE)
    1561       49974 :                 token = aTYPE;
    1562             : 
    1563    29220356 :         if (token == IDENT || token == COMPARISON ||
    1564    23678880 :             token == RANK || token == aTYPE || token == MARGFUNC) {
    1565     5602089 :                 yylval->sval = sa_strndup(c->sa, yylval->sval, lc->yycur-lc->yysval);
    1566     5602096 :                 lc->next_string_is_raw = false;
    1567    23618267 :         } else if (token == STRING) {
    1568     2160751 :                 char quote = *yylval->sval;
    1569     2160751 :                 char *str = sa_alloc( c->sa, (lc->yycur-lc->yysval-2)*2 + 1 );
    1570     2160751 :                 char *dst;
    1571             : 
    1572     2160751 :                 assert(quote == '"' || quote == '\'' || quote == 'E' || quote == 'e' || quote == 'U' || quote == 'u' || quote == 'X' || quote == 'x' || quote == 'R' || quote == 'r');
    1573             : 
    1574     2160751 :                 lc->rs->buf[lc->rs->pos + lc->yycur - 1] = 0;
    1575     2160751 :                 switch (quote) {
    1576     1330140 :                 case '"':
    1577     1330140 :                         if (valid_ident(yylval->sval+1,str)) {
    1578             :                                 token = IDENT;
    1579             :                         } else {
    1580           0 :                                 sql_error(c, 1, SQLSTATE(42000) "Invalid identifier '%s'", yylval->sval+1);
    1581           0 :                                 return LEX_ERROR;
    1582             :                         }
    1583             :                         break;
    1584        3914 :                 case 'e':
    1585             :                 case 'E':
    1586        3914 :                         assert(yylval->sval[1] == '\'');
    1587        3914 :                         if (GDKstrFromStr((unsigned char *) str,
    1588             :                                                           (unsigned char *) yylval->sval + 2,
    1589        3914 :                                                           lc->yycur-lc->yysval - 2, '\'') < 0) {
    1590           1 :                                 char *err = GDKerrbuf;
    1591           1 :                                 if (strncmp(err, GDKERROR, strlen(GDKERROR)) == 0)
    1592           1 :                                         err += strlen(GDKERROR);
    1593           0 :                                 else if (*err == '!')
    1594           0 :                                         err++;
    1595           1 :                                 sql_error(c, 1, SQLSTATE(42000) "%s", err);
    1596           1 :                                 return LEX_ERROR;
    1597             :                         }
    1598             :                         quote = '\'';
    1599             :                         break;
    1600          17 :                 case 'u':
    1601             :                 case 'U':
    1602          17 :                         assert(yylval->sval[1] == '&');
    1603          17 :                         assert(yylval->sval[2] == '\'' || yylval->sval[2] == '"');
    1604          17 :                         strcpy(str, yylval->sval + 3);
    1605          17 :                         token = yylval->sval[2] == '\'' ? -STRING : -IDENT; /* Passing unicode string/ident as - numbers, handled
    1606             :                                                                                                                                    later in scanner */
    1607          17 :                         quote = yylval->sval[2];
    1608          17 :                         lc->next_string_is_raw = true;
    1609          17 :                         break;
    1610           1 :                 case 'x':
    1611             :                 case 'X':
    1612           1 :                         assert(yylval->sval[1] == '\'');
    1613           1 :                         dst = str;
    1614           5 :                         for (char *src = yylval->sval + 2; *src; dst++)
    1615           4 :                                 if ((*dst = *src++) == '\'' && *src == '\'')
    1616           0 :                                         src++;
    1617           1 :                         *dst = 0;
    1618           1 :                         quote = '\'';
    1619           1 :                         token = XSTRING;
    1620           1 :                         lc->next_string_is_raw = true;
    1621           1 :                         break;
    1622        3285 :                 case 'r':
    1623             :                 case 'R':
    1624        3285 :                         assert(yylval->sval[1] == '\'');
    1625        3285 :                         dst = str;
    1626      450421 :                         for (char *src = yylval->sval + 2; *src; dst++)
    1627      447136 :                                 if ((*dst = *src++) == '\'' && *src == '\'')
    1628        2780 :                                         src++;
    1629        3285 :                         quote = '\'';
    1630        3285 :                         *dst = 0;
    1631        3285 :                         break;
    1632      823394 :                 default:
    1633      823394 :                         if (lc->raw_string_mode || lc->next_string_is_raw) {
    1634          50 :                                 dst = str;
    1635         479 :                                 for (char *src = yylval->sval + 1; *src; dst++)
    1636         429 :                                         if ((*dst = *src++) == '\'' && *src == '\'')
    1637           3 :                                                 src++;
    1638          50 :                                 *dst = 0;
    1639             :                         } else {
    1640      823344 :                                 if (GDKstrFromStr((unsigned char *)str,
    1641      823344 :                                                                   (unsigned char *)yylval->sval + 1,
    1642      823344 :                                                                   lc->yycur - lc->yysval - 1,
    1643             :                                                                   '\'') < 0) {
    1644           1 :                                         sql_error(c, 1, SQLSTATE(42000) "%s", GDKerrbuf);
    1645           1 :                                         return LEX_ERROR;
    1646             :                                 }
    1647             :                         }
    1648             :                         break;
    1649             :                 }
    1650     2160749 :                 yylval->sval = str;
    1651             : 
    1652             :                 /* reset original */
    1653     2160749 :                 lc->rs->buf[lc->rs->pos+lc->yycur- 1] = quote;
    1654             :         } else {
    1655    21457516 :                 lc->next_string_is_raw = false;
    1656             :         }
    1657             : 
    1658             :         return(token);
    1659             : }
    1660             : 
    1661             : static int scanner( YYSTYPE *yylval, void *m, bool log);
    1662             : 
    1663             : static int
    1664    29184037 : scanner(YYSTYPE * yylval, void *parm, bool log)
    1665             : {
    1666    29184037 :         int token;
    1667    29184037 :         mvc *c = (mvc *) parm;
    1668    29184037 :         struct scanner *lc = &c->scanner;
    1669    29184037 :         size_t pos;
    1670    29184037 :         int last = lc->yyval;
    1671             : 
    1672             :         /* store position for when view's query ends */
    1673    29184037 :         pos = lc->rs->pos + lc->yycur;
    1674             : 
    1675    29184037 :         token = sql_get_next_token(yylval, parm);
    1676             :         /* TODO make hash out of the possible complex tokens and add with current tokens hash */
    1677             : 
    1678    29184970 :         if (token == -IDENT || token == -STRING) {
    1679          17 :                 char *sval = yylval->sval;
    1680          17 :                 int next = sql_get_next_token(yylval, parm);
    1681             : 
    1682          17 :                 if (token == -STRING && next == STRING) {
    1683           2 :                         sval = sa_strconcat(c->sa, sval, yylval->sval);
    1684           6 :                         while((next = sql_get_next_token(yylval, parm)) == STRING)
    1685           4 :                                 sval = sa_strconcat(c->sa, sval, yylval->sval);
    1686             :                 }
    1687             : 
    1688          17 :                 char *uescape = "\\";
    1689          17 :                 if (next == UESCAPE) {
    1690          14 :                         int nxt = sql_get_next_token(yylval, parm);
    1691          14 :                         if (nxt == STRING) {
    1692          14 :                                 next = 0;
    1693          14 :                                 uescape = yylval->sval;
    1694          14 :                 if (strlen(uescape) != 1 || strchr("\"'0123456789abcdefABCDEF+ \t\n\r\f", *uescape) != NULL) {
    1695           0 :                     sqlformaterror(c, SQLSTATE(22019) "%s", "UESCAPE must be one character");
    1696           0 :                                         return LEX_ERROR;
    1697             :                 }
    1698             :                         } else {
    1699           0 :                 sqlformaterror(c, SQLSTATE(22019) "%s", "UESCAPE character missing");
    1700           0 :                                 return LEX_ERROR;
    1701             :                         }
    1702             :                 }
    1703          17 :                 yylval->sval = uescape_xform(sval, uescape);
    1704          17 :                 if (yylval->sval == NULL && token == -STRING) {
    1705           0 :                         sqlformaterror(c, SQLSTATE(22019) "%s", "Bad Unicode string");
    1706           0 :                         return LEX_ERROR;
    1707             :                 }
    1708             : 
    1709          17 :                 if (next)
    1710           3 :                         lc->yynext = next;
    1711          17 :                 return (token == -IDENT)?IDENT:STRING;
    1712    29184953 :         } else if (token == WITH) { /* check for TIME WITH ... */
    1713       15572 :                 int next = sql_get_next_token(yylval, parm);
    1714       15572 :                 if (next == TIME)
    1715        5416 :                         token = WITH_LA;
    1716       15572 :                 lc->yynext = next;
    1717    29169381 :         } else if (token == INTO) { /* check for INTO followed by STRING / (BIG/LITTLE/NATIVE) for copy into file vs copy select into var */
    1718      139811 :                 int next = sql_get_next_token(yylval, parm);
    1719      139810 :                 if (next == STRING || next == BIG || next == LITTLE || next == NATIVE ||
    1720             :                         next == BINARY || next == STDOUT)
    1721          77 :                         token = INTO_LA;
    1722      139810 :                 lc->yynext = next;
    1723    29029570 :         } else if (last == ODBC_FUNC_ESCAPE_PREFIX && token == TIMESTAMPADD) {
    1724             :                 token = ODBC_TIMESTAMPADD;
    1725    29029552 :         } else if (last == ODBC_FUNC_ESCAPE_PREFIX && token == TIMESTAMPDIFF) {
    1726             :                 token = ODBC_TIMESTAMPDIFF;
    1727    29029464 :         } else if (last == INTERVAL && (token == '-' || token == '+')) { /* backward compatibility: INTERVAL +- 'string' -> interval '+-string'*/
    1728          12 :                 int next = sql_get_next_token(yylval, parm);
    1729          12 :                 if (next == STRING) {
    1730          12 :                         if (token != '+') {
    1731           8 :                                 char *sval = yylval->sval;
    1732           8 :                                 if (sval[0] == '+')
    1733           0 :                                         sval[0] = '-';
    1734           8 :                                 else if (sval[0] == '-')
    1735           1 :                                                 yylval->sval++;
    1736             :                                 else
    1737           7 :                                         yylval->sval = sa_strconcat(c->sa, token=='-'?"-":"+", sval);
    1738             :                         }
    1739             :                         token = next;
    1740             :                         next = 0;
    1741             :                 }
    1742          12 :                 lc->yynext = next;
    1743    29029452 :         } else if (token == OUTER) { /* check for OUTER UNION */
    1744       18426 :                 int next = sql_get_next_token(yylval, parm);
    1745       18426 :                 if (next == UNION)
    1746             :                         token = OUTER_UNION;
    1747             :                 else
    1748       18417 :                         lc->yynext = next;
    1749    29011026 :         } else if (token == TO) { /* check for end_field (of interval spec) TO (MONTH etc) */
    1750      121026 :                 int next = sql_get_next_token(yylval, parm);
    1751      121026 :                 if (next == YEAR || next == MONTH || next == DAY || next == HOUR || next == MINUTE || next == SECOND)
    1752         273 :                         token = TO_LA;
    1753      121026 :                 lc->yynext = next;
    1754    28890000 :         } else if (token == NOT) {
    1755       77712 :                 int next = sql_get_next_token(yylval, parm);
    1756             : 
    1757       77712 :                 if (next == NOT) {
    1758           2 :                         return scanner(yylval, parm, false);
    1759             :                 } else if (next == EXISTS) {
    1760             :                         token = NOT_EXISTS;
    1761             :                 } else if (next == BETWEEN) {
    1762             :                         token = NOT_BETWEEN;
    1763             :                 } else if (next == sqlIN) {
    1764             :                         token = NOT_IN;
    1765             :                 } else if (next == LIKE) {
    1766             :                         token = NOT_LIKE;
    1767             :                 } else if (next == ILIKE) {
    1768             :                         token = NOT_ILIKE;
    1769             :                 } else {
    1770       63245 :                         lc->yynext = next;
    1771             :                 }
    1772    28812288 :         } else if (token == SCOLON) {
    1773             :                 /* ignore semi-colon(s) following a semi-colon */
    1774     1043613 :                 if (lc->yylast == SCOLON) {
    1775      132017 :                         size_t prev = lc->yycur;
    1776      132018 :                         while ((token = sql_get_next_token(yylval, parm)) == SCOLON)
    1777           1 :                                 prev = lc->yycur;
    1778             : 
    1779             :                         /* skip the skipped stuff also in the buffer */
    1780      132017 :                         lc->rs->pos += prev;
    1781      132017 :                         lc->yycur -= prev;
    1782             :                 }
    1783             :         }
    1784             : 
    1785    29184950 :         if (lc->log && log)
    1786           0 :                 mnstr_write(lc->log, lc->rs->buf+pos, lc->rs->pos + lc->yycur - pos, 1);
    1787             : 
    1788    29184950 :         lc->started += (token != EOF);
    1789    29184950 :         return token;
    1790             : }
    1791             : 
    1792             : /* also see sql_parser.y */
    1793             : extern int sqllex(YYSTYPE * yylval, void *parm);
    1794             : 
    1795             : int
    1796    29184472 : sqllex(YYSTYPE * yylval, void *parm)
    1797             : {
    1798    29184472 :         return scanner(yylval, parm, true);
    1799             : }

Generated by: LCOV version 1.14