Example #1
0
/*
** If the input string begins with "<html>" and contains "</html>" somewhere
** before it ends, then return the number of characters through the end of
** the </html>.  If the <html> or the </html> is missing, return 0.
*/
static int is_html(const char *z){
  int i;
  extern int sqliteStrNICmp(const char *, const char*, int);
  if( sqliteStrNICmp(z, "<html>", 6) ) return 0;
  for(i=6; z[i]; i++){
    if( z[i]=='<' && sqliteStrNICmp(&z[i],"</html>",7)==0 ) return i+7;
  }
  return 0;
}
Example #2
0
/*
** This function looks up an identifier to determine if it is a
** keyword.  If it is a keyword, the token code of that keyword is 
** returned.  If the input is not a keyword, TK_ID is returned.
*/
int sqliteKeywordCode(const char *z, int n){
  int h, i;
  Keyword *p;
  static char needInit = 1;
  if( needInit ){
    /* Initialize the keyword hash table */
    sqliteOsEnterMutex();
    if( needInit ){
      int nk;
      nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
      for(i=0; i<nk; i++){
        aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
        h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
        h %= KEY_HASH_SIZE;
        aKeywordTable[i].iNext = aiHashTable[h];
        aiHashTable[h] = i+1;
      }
      needInit = 0;
    }
    sqliteOsLeaveMutex();
  }
  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
  for(i=aiHashTable[h]; i; i=p->iNext){
    p = &aKeywordTable[i-1];
    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
      return p->tokenType;
    }
  }
  return TK_ID;
}
Example #3
0
/*
** Do a deep comparison of two expression trees.  Return TRUE (non-zero)
** if they are identical and return FALSE if they differ in any way.
*/
int sqliteExprCompare(Expr *pA, Expr *pB){
  int i;
  if( pA==0 ){
    return pB==0;
  }else if( pB==0 ){
    return 0;
  }
  if( pA->op!=pB->op ) return 0;
  if( !sqliteExprCompare(pA->pLeft, pB->pLeft) ) return 0;
  if( !sqliteExprCompare(pA->pRight, pB->pRight) ) return 0;
  if( pA->pList ){
    if( pB->pList==0 ) return 0;
    if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
    for(i=0; i<pA->pList->nExpr; i++){
      if( !sqliteExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
        return 0;
      }
    }
  }else if( pB->pList ){
    return 0;
  }
  if( pA->pSelect || pB->pSelect ) return 0;
  if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
  if( pA->token.z ){
    if( pB->token.z==0 ) return 0;
    if( pB->token.n!=pA->token.n ) return 0;
    if( sqliteStrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
  }
  return 1;
}
Example #4
0
/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon.  The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int _is_command_terminator(const char *zLine){
  extern int sqliteStrNICmp(const char*,const char*,int);
  while( isspace(*zLine) ){ zLine++; };
  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ) return 1;  /* Oracle */
  if( sqliteStrNICmp(zLine,"go",2)==0 && _all_whitespace(&zLine[2]) ){
    return 1;  /* SQL Server */
  }
  return 0;
}
Example #5
0
/*
** This routine is called by the parser to process a DETACH statement:
**
**    DETACH DATABASE dbname
**
** The pDbname argument is the name of the database in the DETACH statement.
*/
void sqliteDetach(Parse *pParse, Token *pDbname){
  int i;
  sqlite *db;
  Vdbe *v;
  Db *pDb;

  v = sqliteGetVdbe(pParse);
  sqliteVdbeAddOp(v, OP_Halt, 0, 0);
  if( pParse->explain ) return;
  db = pParse->db;
  for(i=0; i<db->nDb; i++){
    pDb = &db->aDb[i];
    if( pDb->pBt==0 || pDb->zName==0 ) continue;
    if( strlen(pDb->zName)!=pDbname->n ) continue;
    if( sqliteStrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
  }
  if( i>=db->nDb ){
    sqliteErrorMsg(pParse, "no such database: %T", pDbname);
    return;
  }
  if( i<2 ){
    sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
    return;
  }
#ifndef SQLITE_OMIT_AUTHORIZATION
  if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
    return;
  }
#endif /* SQLITE_OMIT_AUTHORIZATION */
  sqliteBtreeClose(pDb->pBt);
  pDb->pBt = 0;
  sqliteFree(pDb->zName);
  sqliteResetInternalSchema(db, i);
  if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
  db->nDb--;
  if( i<db->nDb ){
    db->aDb[i] = db->aDb[db->nDb];
    memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
    sqliteResetInternalSchema(db, i);
  }
}
Example #6
0
/*
** Return TRUE if the given SQL string ends in a semicolon.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
** This implementation uses a state machine with 7 states:
**
**   (0) START     At the beginning or end of an SQL statement.  This routine
**                 returns 1 if it ends in the START state and 0 if it ends
**                 in any other state.
**
**   (1) EXPLAIN   The keyword EXPLAIN has been seen at the beginning of 
**                 a statement.
**
**   (2) CREATE    The keyword CREATE has been seen at the beginning of a
**                 statement, possibly preceeded by EXPLAIN and/or followed by
**                 TEMP or TEMPORARY
**
**   (3) NORMAL    We are in the middle of statement which ends with a single
**                 semicolon.
**
**   (4) TRIGGER   We are in the middle of a trigger definition that must be
**                 ended by a semicolon, the keyword END, and another semicolon.
**
**   (5) SEMI      We've seen the first semicolon in the ";END;" that occurs at
**                 the end of a trigger definition.
**
**   (6) END       We've seen the ";END" of the ";END;" that occurs at the end
**                 of a trigger difinition.
**
** Transitions between states above are determined by tokens extracted
** from the input.  The following tokens are significant:
**
**   (0) tkEXPLAIN   The "explain" keyword.
**   (1) tkCREATE    The "create" keyword.
**   (2) tkTEMP      The "temp" or "temporary" keyword.
**   (3) tkTRIGGER   The "trigger" keyword.
**   (4) tkEND       The "end" keyword.
**   (5) tkSEMI      A semicolon.
**   (6) tkWS        Whitespace
**   (7) tkOTHER     Any other SQL token.
**
** Whitespace never causes a state transition and is always ignored.
*/
int sqlite_complete(const char *zSql){
  u8 state = 0;   /* Current state, using numbers defined in header comment */
  u8 token;       /* Value of the next token */

  /* The following matrix defines the transition from one state to another
  ** according to what token is seen.  trans[state][token] returns the
  ** next state.
  */
  static const u8 trans[7][8] = {
                     /* Token:                                                */
     /* State:       **  EXPLAIN  CREATE  TEMP  TRIGGER  END  SEMI  WS  OTHER */
     /* 0   START: */ {       1,      2,    3,       3,   3,    0,  0,     3, },
     /* 1 EXPLAIN: */ {       3,      2,    3,       3,   3,    0,  1,     3, },
     /* 2  CREATE: */ {       3,      3,    2,       4,   3,    0,  2,     3, },
     /* 3  NORMAL: */ {       3,      3,    3,       3,   3,    0,  3,     3, },
     /* 4 TRIGGER: */ {       4,      4,    4,       4,   4,    5,  4,     4, },
     /* 5    SEMI: */ {       4,      4,    4,       4,   6,    5,  5,     4, },
     /* 6     END: */ {       4,      4,    4,       4,   4,    0,  6,     4, },
  };

  while( *zSql ){
    switch( *zSql ){
      case ';': {  /* A semicolon */
        token = tkSEMI;
        break;
      }
      case ' ':
      case '\r':
      case '\t':
      case '\n':
      case '\f': {  /* White space is ignored */
        token = tkWS;
        break;
      }
      case '/': {   /* C-style comments */
        if( zSql[1]!='*' ){
          token = tkOTHER;
          break;
        }
        zSql += 2;
        while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
        if( zSql[0]==0 ) return 0;
        zSql++;
        token = tkWS;
        break;
      }
      case '-': {   /* SQL-style comments from "--" to end of line */
        if( zSql[1]!='-' ){
          token = tkOTHER;
          break;
        }
        while( *zSql && *zSql!='\n' ){ zSql++; }
        if( *zSql==0 ) return state==0;
        token = tkWS;
        break;
      }
      case '[': {   /* Microsoft-style identifiers in [...] */
        zSql++;
        while( *zSql && *zSql!=']' ){ zSql++; }
        if( *zSql==0 ) return 0;
        token = tkOTHER;
        break;
      }
      case '"':     /* single- and double-quoted strings */
      case '\'': {
        int c = *zSql;
        zSql++;
        while( *zSql && *zSql!=c ){ zSql++; }
        if( *zSql==0 ) return 0;
        token = tkOTHER;
        break;
      }
      default: {
        if( isIdChar[(u8)*zSql] ){
          /* Keywords and unquoted identifiers */
          int nId;
          for(nId=1; isIdChar[(u8)zSql[nId]]; nId++){}
          switch( *zSql ){
            case 'c': case 'C': {
              if( nId==6 && sqliteStrNICmp(zSql, "create", 6)==0 ){
                token = tkCREATE;
              }else{
                token = tkOTHER;
              }
              break;
            }
            case 't': case 'T': {
              if( nId==7 && sqliteStrNICmp(zSql, "trigger", 7)==0 ){
                token = tkTRIGGER;
              }else if( nId==4 && sqliteStrNICmp(zSql, "temp", 4)==0 ){
                token = tkTEMP;
              }else if( nId==9 && sqliteStrNICmp(zSql, "temporary", 9)==0 ){
                token = tkTEMP;
              }else{
                token = tkOTHER;
              }
              break;
            }
            case 'e':  case 'E': {
              if( nId==3 && sqliteStrNICmp(zSql, "end", 3)==0 ){
                token = tkEND;
              }else if( nId==7 && sqliteStrNICmp(zSql, "explain", 7)==0 ){
                token = tkEXPLAIN;
              }else{
                token = tkOTHER;
              }
              break;
            }
            default: {
              token = tkOTHER;
              break;
            }
          }
          zSql += nId-1;
        }else{
          /* Operators and special symbols */
          token = tkOTHER;
        }
        break;
      }
    }
    state = trans[state][token];
    zSql++;
  }
  return state==0;
}
Example #7
0
/*
** This is called by the parser when it sees a CREATE TRIGGER statement
** up to the point of the BEGIN before the trigger actions.  A Trigger
** structure is generated based on the information available and stored
** in pParse->pNewTrigger.  After the trigger actions have been parsed, the
** sqliteFinishTrigger() function is called to complete the trigger
** construction process.
*/
void sqliteBeginTrigger(
  Parse *pParse,      /* The parse context of the CREATE TRIGGER statement */
  Token *pName,       /* The name of the trigger */
  int tr_tm,          /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
  int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
  IdList *pColumns,   /* column list if this is an UPDATE OF trigger */
  SrcList *pTableName,/* The name of the table/view the trigger applies to */
  int foreach,        /* One of TK_ROW or TK_STATEMENT */
  Expr *pWhen,        /* WHEN clause */
  int isTemp          /* True if the TEMPORARY keyword is present */
){
  Trigger *nt;
  Table   *tab;
  char *zName = 0;        /* Name of the trigger */
  sqlite *db = pParse->db;
  int iDb;                /* When database to store the trigger in */
  DbFixer sFix;

  /* Check that: 
  ** 1. the trigger name does not already exist.
  ** 2. the table (or view) does exist in the same database as the trigger.
  ** 3. that we are not trying to create a trigger on the sqlite_master table
  ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
  ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
  */
  if( sqlite_malloc_failed ) goto trigger_cleanup;
  assert( pTableName->nSrc==1 );
  if( db->init.busy
   && sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
   && sqliteFixSrcList(&sFix, pTableName)
  ){
    goto trigger_cleanup;
  }
  tab = sqliteSrcListLookup(pParse, pTableName);
  if( !tab ){
    goto trigger_cleanup;
  }
  iDb = isTemp ? 1 : tab->iDb;
  if( iDb>=2 && !db->init.busy ){
    sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
       "database %s", db->aDb[tab->iDb].zName);
    goto trigger_cleanup;
  }

  zName = sqliteStrNDup(pName->z, pName->n);
  sqliteDequote(zName);
  if( sqliteHashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
    sqliteErrorMsg(pParse, "trigger %T already exists", pName);
    goto trigger_cleanup;
  }
  if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
    sqliteErrorMsg(pParse, "cannot create trigger on system table");
    pParse->nErr++;
    goto trigger_cleanup;
  }
  if( tab->pSelect && tr_tm != TK_INSTEAD ){
    sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S", 
        (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
    goto trigger_cleanup;
  }
  if( !tab->pSelect && tr_tm == TK_INSTEAD ){
    sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
        " trigger on table: %S", pTableName, 0);
    goto trigger_cleanup;
  }
#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    int code = SQLITE_CREATE_TRIGGER;
    const char *zDb = db->aDb[tab->iDb].zName;
    const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
    if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
    if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){
      goto trigger_cleanup;
    }
    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){
      goto trigger_cleanup;
    }
  }
#endif

  /* INSTEAD OF triggers can only appear on views and BEGIN triggers
  ** cannot appear on views.  So we might as well translate every
  ** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
  ** elsewhere.
  */
  if (tr_tm == TK_INSTEAD){
    tr_tm = TK_BEFORE;
  }

  /* Build the Trigger object */
  nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
  if( nt==0 ) goto trigger_cleanup;
  nt->name = zName;
  zName = 0;
  nt->table = sqliteStrDup(pTableName->a[0].zName);
  if( sqlite_malloc_failed ) goto trigger_cleanup;
  nt->iDb = iDb;
  nt->iTabDb = tab->iDb;
  nt->op = op;
  nt->tr_tm = tr_tm;
  nt->pWhen = sqliteExprDup(pWhen);
  nt->pColumns = sqliteIdListDup(pColumns);
  nt->foreach = foreach;
  sqliteTokenCopy(&nt->nameToken,pName);
  assert( pParse->pNewTrigger==0 );
  pParse->pNewTrigger = nt;

trigger_cleanup:
  sqliteFree(zName);
  sqliteSrcListDelete(pTableName);
  sqliteIdListDelete(pColumns);
  sqliteExprDelete(pWhen);
}