extensions/sqlite/sqlite-source/complete.c
author David Anderson <dvander@alliedmods.net>
Sun Oct 28 05:48:06 2007 +0000 (2007-10-28)
changeset 1645 27307df4d711
parent 1203 633c25ce6405
permissions -rw-r--r--
updated to sqlite-3.5.1 now that it's stable
used new shared cache functionality (yay)
dvander@1203
     1
/*
dvander@1203
     2
** 2001 September 15
dvander@1203
     3
**
dvander@1203
     4
** The author disclaims copyright to this source code.  In place of
dvander@1203
     5
** a legal notice, here is a blessing:
dvander@1203
     6
**
dvander@1203
     7
**    May you do good and not evil.
dvander@1203
     8
**    May you find forgiveness for yourself and forgive others.
dvander@1203
     9
**    May you share freely, never taking more than you give.
dvander@1203
    10
**
dvander@1203
    11
*************************************************************************
dvander@1203
    12
** An tokenizer for SQL
dvander@1203
    13
**
dvander@1203
    14
** This file contains C code that implements the sqlite3_complete() API.
dvander@1203
    15
** This code used to be part of the tokenizer.c source file.  But by
dvander@1203
    16
** separating it out, the code will be automatically omitted from
dvander@1203
    17
** static links that do not use it.
dvander@1203
    18
**
dvander@1203
    19
** $Id$
dvander@1203
    20
*/
dvander@1203
    21
#include "sqliteInt.h"
dvander@1203
    22
#ifndef SQLITE_OMIT_COMPLETE
dvander@1203
    23
dvander@1203
    24
/*
dvander@1203
    25
** This is defined in tokenize.c.  We just have to import the definition.
dvander@1203
    26
*/
dvander@1645
    27
#ifndef SQLITE_AMALGAMATION
dvander@1645
    28
#ifdef SQLITE_ASCII
dvander@1645
    29
extern const char sqlite3IsAsciiIdChar[];
dvander@1645
    30
#define IdChar(C)  (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
dvander@1645
    31
#endif
dvander@1645
    32
#ifdef SQLITE_EBCDIC
dvander@1645
    33
extern const char sqlite3IsEbcdicIdChar[];
dvander@1645
    34
#define IdChar(C)  (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
dvander@1645
    35
#endif
dvander@1645
    36
#endif /* SQLITE_AMALGAMATION */
dvander@1203
    37
dvander@1203
    38
dvander@1203
    39
/*
dvander@1203
    40
** Token types used by the sqlite3_complete() routine.  See the header
dvander@1203
    41
** comments on that procedure for additional information.
dvander@1203
    42
*/
dvander@1203
    43
#define tkSEMI    0
dvander@1203
    44
#define tkWS      1
dvander@1203
    45
#define tkOTHER   2
dvander@1203
    46
#define tkEXPLAIN 3
dvander@1203
    47
#define tkCREATE  4
dvander@1203
    48
#define tkTEMP    5
dvander@1203
    49
#define tkTRIGGER 6
dvander@1203
    50
#define tkEND     7
dvander@1203
    51
dvander@1203
    52
/*
dvander@1203
    53
** Return TRUE if the given SQL string ends in a semicolon.
dvander@1203
    54
**
dvander@1203
    55
** Special handling is require for CREATE TRIGGER statements.
dvander@1203
    56
** Whenever the CREATE TRIGGER keywords are seen, the statement
dvander@1203
    57
** must end with ";END;".
dvander@1203
    58
**
dvander@1203
    59
** This implementation uses a state machine with 7 states:
dvander@1203
    60
**
dvander@1203
    61
**   (0) START     At the beginning or end of an SQL statement.  This routine
dvander@1203
    62
**                 returns 1 if it ends in the START state and 0 if it ends
dvander@1203
    63
**                 in any other state.
dvander@1203
    64
**
dvander@1203
    65
**   (1) NORMAL    We are in the middle of statement which ends with a single
dvander@1203
    66
**                 semicolon.
dvander@1203
    67
**
dvander@1203
    68
**   (2) EXPLAIN   The keyword EXPLAIN has been seen at the beginning of 
dvander@1203
    69
**                 a statement.
dvander@1203
    70
**
dvander@1203
    71
**   (3) CREATE    The keyword CREATE has been seen at the beginning of a
dvander@1203
    72
**                 statement, possibly preceeded by EXPLAIN and/or followed by
dvander@1203
    73
**                 TEMP or TEMPORARY
dvander@1203
    74
**
dvander@1203
    75
**   (4) TRIGGER   We are in the middle of a trigger definition that must be
dvander@1203
    76
**                 ended by a semicolon, the keyword END, and another semicolon.
dvander@1203
    77
**
dvander@1203
    78
**   (5) SEMI      We've seen the first semicolon in the ";END;" that occurs at
dvander@1203
    79
**                 the end of a trigger definition.
dvander@1203
    80
**
dvander@1203
    81
**   (6) END       We've seen the ";END" of the ";END;" that occurs at the end
dvander@1203
    82
**                 of a trigger difinition.
dvander@1203
    83
**
dvander@1203
    84
** Transitions between states above are determined by tokens extracted
dvander@1203
    85
** from the input.  The following tokens are significant:
dvander@1203
    86
**
dvander@1203
    87
**   (0) tkSEMI      A semicolon.
dvander@1203
    88
**   (1) tkWS        Whitespace
dvander@1203
    89
**   (2) tkOTHER     Any other SQL token.
dvander@1203
    90
**   (3) tkEXPLAIN   The "explain" keyword.
dvander@1203
    91
**   (4) tkCREATE    The "create" keyword.
dvander@1203
    92
**   (5) tkTEMP      The "temp" or "temporary" keyword.
dvander@1203
    93
**   (6) tkTRIGGER   The "trigger" keyword.
dvander@1203
    94
**   (7) tkEND       The "end" keyword.
dvander@1203
    95
**
dvander@1203
    96
** Whitespace never causes a state transition and is always ignored.
dvander@1203
    97
**
dvander@1203
    98
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
dvander@1203
    99
** to recognize the end of a trigger can be omitted.  All we have to do
dvander@1203
   100
** is look for a semicolon that is not part of an string or comment.
dvander@1203
   101
*/
dvander@1203
   102
int sqlite3_complete(const char *zSql){
dvander@1203
   103
  u8 state = 0;   /* Current state, using numbers defined in header comment */
dvander@1203
   104
  u8 token;       /* Value of the next token */
dvander@1203
   105
dvander@1203
   106
#ifndef SQLITE_OMIT_TRIGGER
dvander@1203
   107
  /* A complex statement machine used to detect the end of a CREATE TRIGGER
dvander@1203
   108
  ** statement.  This is the normal case.
dvander@1203
   109
  */
dvander@1203
   110
  static const u8 trans[7][8] = {
dvander@1203
   111
                     /* Token:                                                */
dvander@1203
   112
     /* State:       **  SEMI  WS  OTHER EXPLAIN  CREATE  TEMP  TRIGGER  END  */
dvander@1203
   113
     /* 0   START: */ {    0,  0,     1,      2,      3,    1,       1,   1,  },
dvander@1203
   114
     /* 1  NORMAL: */ {    0,  1,     1,      1,      1,    1,       1,   1,  },
dvander@1203
   115
     /* 2 EXPLAIN: */ {    0,  2,     1,      1,      3,    1,       1,   1,  },
dvander@1203
   116
     /* 3  CREATE: */ {    0,  3,     1,      1,      1,    3,       4,   1,  },
dvander@1203
   117
     /* 4 TRIGGER: */ {    5,  4,     4,      4,      4,    4,       4,   4,  },
dvander@1203
   118
     /* 5    SEMI: */ {    5,  5,     4,      4,      4,    4,       4,   6,  },
dvander@1203
   119
     /* 6     END: */ {    0,  6,     4,      4,      4,    4,       4,   4,  },
dvander@1203
   120
  };
dvander@1203
   121
#else
dvander@1203
   122
  /* If triggers are not suppored by this compile then the statement machine
dvander@1203
   123
  ** used to detect the end of a statement is much simplier
dvander@1203
   124
  */
dvander@1203
   125
  static const u8 trans[2][3] = {
dvander@1203
   126
                     /* Token:           */
dvander@1203
   127
     /* State:       **  SEMI  WS  OTHER */
dvander@1203
   128
     /* 0   START: */ {    0,  0,     1, },
dvander@1203
   129
     /* 1  NORMAL: */ {    0,  1,     1, },
dvander@1203
   130
  };
dvander@1203
   131
#endif /* SQLITE_OMIT_TRIGGER */
dvander@1203
   132
dvander@1203
   133
  while( *zSql ){
dvander@1203
   134
    switch( *zSql ){
dvander@1203
   135
      case ';': {  /* A semicolon */
dvander@1203
   136
        token = tkSEMI;
dvander@1203
   137
        break;
dvander@1203
   138
      }
dvander@1203
   139
      case ' ':
dvander@1203
   140
      case '\r':
dvander@1203
   141
      case '\t':
dvander@1203
   142
      case '\n':
dvander@1203
   143
      case '\f': {  /* White space is ignored */
dvander@1203
   144
        token = tkWS;
dvander@1203
   145
        break;
dvander@1203
   146
      }
dvander@1203
   147
      case '/': {   /* C-style comments */
dvander@1203
   148
        if( zSql[1]!='*' ){
dvander@1203
   149
          token = tkOTHER;
dvander@1203
   150
          break;
dvander@1203
   151
        }
dvander@1203
   152
        zSql += 2;
dvander@1203
   153
        while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
dvander@1203
   154
        if( zSql[0]==0 ) return 0;
dvander@1203
   155
        zSql++;
dvander@1203
   156
        token = tkWS;
dvander@1203
   157
        break;
dvander@1203
   158
      }
dvander@1203
   159
      case '-': {   /* SQL-style comments from "--" to end of line */
dvander@1203
   160
        if( zSql[1]!='-' ){
dvander@1203
   161
          token = tkOTHER;
dvander@1203
   162
          break;
dvander@1203
   163
        }
dvander@1203
   164
        while( *zSql && *zSql!='\n' ){ zSql++; }
dvander@1203
   165
        if( *zSql==0 ) return state==0;
dvander@1203
   166
        token = tkWS;
dvander@1203
   167
        break;
dvander@1203
   168
      }
dvander@1203
   169
      case '[': {   /* Microsoft-style identifiers in [...] */
dvander@1203
   170
        zSql++;
dvander@1203
   171
        while( *zSql && *zSql!=']' ){ zSql++; }
dvander@1203
   172
        if( *zSql==0 ) return 0;
dvander@1203
   173
        token = tkOTHER;
dvander@1203
   174
        break;
dvander@1203
   175
      }
dvander@1203
   176
      case '`':     /* Grave-accent quoted symbols used by MySQL */
dvander@1203
   177
      case '"':     /* single- and double-quoted strings */
dvander@1203
   178
      case '\'': {
dvander@1203
   179
        int c = *zSql;
dvander@1203
   180
        zSql++;
dvander@1203
   181
        while( *zSql && *zSql!=c ){ zSql++; }
dvander@1203
   182
        if( *zSql==0 ) return 0;
dvander@1203
   183
        token = tkOTHER;
dvander@1203
   184
        break;
dvander@1203
   185
      }
dvander@1203
   186
      default: {
dvander@1203
   187
        int c;
dvander@1203
   188
        if( IdChar((u8)*zSql) ){
dvander@1203
   189
          /* Keywords and unquoted identifiers */
dvander@1203
   190
          int nId;
dvander@1203
   191
          for(nId=1; IdChar(zSql[nId]); nId++){}
dvander@1203
   192
#ifdef SQLITE_OMIT_TRIGGER
dvander@1203
   193
          token = tkOTHER;
dvander@1203
   194
#else
dvander@1203
   195
          switch( *zSql ){
dvander@1203
   196
            case 'c': case 'C': {
dvander@1203
   197
              if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
dvander@1203
   198
                token = tkCREATE;
dvander@1203
   199
              }else{
dvander@1203
   200
                token = tkOTHER;
dvander@1203
   201
              }
dvander@1203
   202
              break;
dvander@1203
   203
            }
dvander@1203
   204
            case 't': case 'T': {
dvander@1203
   205
              if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
dvander@1203
   206
                token = tkTRIGGER;
dvander@1203
   207
              }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
dvander@1203
   208
                token = tkTEMP;
dvander@1203
   209
              }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
dvander@1203
   210
                token = tkTEMP;
dvander@1203
   211
              }else{
dvander@1203
   212
                token = tkOTHER;
dvander@1203
   213
              }
dvander@1203
   214
              break;
dvander@1203
   215
            }
dvander@1203
   216
            case 'e':  case 'E': {
dvander@1203
   217
              if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
dvander@1203
   218
                token = tkEND;
dvander@1203
   219
              }else
dvander@1203
   220
#ifndef SQLITE_OMIT_EXPLAIN
dvander@1203
   221
              if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
dvander@1203
   222
                token = tkEXPLAIN;
dvander@1203
   223
              }else
dvander@1203
   224
#endif
dvander@1203
   225
              {
dvander@1203
   226
                token = tkOTHER;
dvander@1203
   227
              }
dvander@1203
   228
              break;
dvander@1203
   229
            }
dvander@1203
   230
            default: {
dvander@1203
   231
              token = tkOTHER;
dvander@1203
   232
              break;
dvander@1203
   233
            }
dvander@1203
   234
          }
dvander@1203
   235
#endif /* SQLITE_OMIT_TRIGGER */
dvander@1203
   236
          zSql += nId-1;
dvander@1203
   237
        }else{
dvander@1203
   238
          /* Operators and special symbols */
dvander@1203
   239
          token = tkOTHER;
dvander@1203
   240
        }
dvander@1203
   241
        break;
dvander@1203
   242
      }
dvander@1203
   243
    }
dvander@1203
   244
    state = trans[state][token];
dvander@1203
   245
    zSql++;
dvander@1203
   246
  }
dvander@1203
   247
  return state==0;
dvander@1203
   248
}
dvander@1203
   249
dvander@1203
   250
#ifndef SQLITE_OMIT_UTF16
dvander@1203
   251
/*
dvander@1203
   252
** This routine is the same as the sqlite3_complete() routine described
dvander@1203
   253
** above, except that the parameter is required to be UTF-16 encoded, not
dvander@1203
   254
** UTF-8.
dvander@1203
   255
*/
dvander@1203
   256
int sqlite3_complete16(const void *zSql){
dvander@1203
   257
  sqlite3_value *pVal;
dvander@1203
   258
  char const *zSql8;
dvander@1645
   259
  int rc = SQLITE_NOMEM;
dvander@1203
   260
dvander@1645
   261
  pVal = sqlite3ValueNew(0);
dvander@1203
   262
  sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
dvander@1203
   263
  zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
dvander@1203
   264
  if( zSql8 ){
dvander@1203
   265
    rc = sqlite3_complete(zSql8);
dvander@1203
   266
  }
dvander@1203
   267
  sqlite3ValueFree(pVal);
dvander@1203
   268
  return sqlite3ApiExit(0, rc);
dvander@1203
   269
}
dvander@1203
   270
#endif /* SQLITE_OMIT_UTF16 */
dvander@1203
   271
#endif /* SQLITE_OMIT_COMPLETE */