The SET STATEMENT ... FOR part can be ignored and the type of the statement be whatever the type of the part following FOR is.
		
			
				
	
	
		
			834 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			834 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
** Compile and run this standalone program in order to generate code that
 | 
						|
** implements a function that will translate alphabetic identifiers into
 | 
						|
** parser token codes.
 | 
						|
*/
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
/*
 | 
						|
** A header comment placed at the beginning of generated code.
 | 
						|
*/
 | 
						|
static const char zHdr[] = 
 | 
						|
  "/***** This file contains automatically generated code ******\n"
 | 
						|
  "**\n"
 | 
						|
  "** The code in this file has been automatically generated by\n"
 | 
						|
  "**\n"
 | 
						|
  "**   sqlite/tool/mkkeywordhash.c\n"
 | 
						|
  "**\n"
 | 
						|
  "** The code in this file implements a function that determines whether\n"
 | 
						|
  "** or not a given identifier is really an SQL keyword.  The same thing\n"
 | 
						|
  "** might be implemented more directly using a hand-written hash table.\n"
 | 
						|
  "** But by using this automatically generated code, the size of the code\n"
 | 
						|
  "** is substantially reduced.  This is important for embedded applications\n"
 | 
						|
  "** on platforms with limited memory.\n"
 | 
						|
  "*/\n"
 | 
						|
;
 | 
						|
 | 
						|
/*
 | 
						|
** All the keywords of the SQL language are stored in a hash
 | 
						|
** table composed of instances of the following structure.
 | 
						|
*/
 | 
						|
typedef struct Keyword Keyword;
 | 
						|
struct Keyword {
 | 
						|
  char *zName;         /* The keyword name */
 | 
						|
  char *zTokenType;    /* Token value for this keyword */
 | 
						|
  int mask;            /* Code this keyword if non-zero */
 | 
						|
  int id;              /* Unique ID for this record */
 | 
						|
  int hash;            /* Hash on the keyword */
 | 
						|
  int offset;          /* Offset to start of name string */
 | 
						|
  int len;             /* Length of this keyword, not counting final \000 */
 | 
						|
  int prefix;          /* Number of characters in prefix */
 | 
						|
  int longestSuffix;   /* Longest suffix that is a prefix on another word */
 | 
						|
  int iNext;           /* Index in aKeywordTable[] of next with same hash */
 | 
						|
  int substrId;        /* Id to another keyword this keyword is embedded in */
 | 
						|
  int substrOffset;    /* Offset into substrId for start of this keyword */
 | 
						|
  char zOrigName[20];  /* Original keyword name before processing */
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
** Define masks used to determine which keywords are allowed
 | 
						|
*/
 | 
						|
#ifdef SQLITE_OMIT_ALTERTABLE
 | 
						|
#  define ALTER      0
 | 
						|
#else
 | 
						|
#  define ALTER      0x00000001
 | 
						|
#endif
 | 
						|
#define ALWAYS       0x00000002
 | 
						|
#ifdef SQLITE_OMIT_ANALYZE
 | 
						|
#  define ANALYZE    0
 | 
						|
#else
 | 
						|
#  define ANALYZE    0x00000004
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_ATTACH
 | 
						|
#  define ATTACH     0
 | 
						|
#else
 | 
						|
#  define ATTACH     0x00000008
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_AUTOINCREMENT
 | 
						|
#  define AUTOINCR   0
 | 
						|
#else
 | 
						|
#  define AUTOINCR   0x00000010
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_CAST
 | 
						|
#  define CAST       0
 | 
						|
#else
 | 
						|
#  define CAST       0x00000020
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_COMPOUND_SELECT
 | 
						|
#  define COMPOUND   0
 | 
						|
#else
 | 
						|
#  define COMPOUND   0x00000040
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
 | 
						|
#  define CONFLICT   0
 | 
						|
#else
 | 
						|
#  define CONFLICT   0x00000080
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_EXPLAIN
 | 
						|
#  define EXPLAIN    0
 | 
						|
#else
 | 
						|
#  define EXPLAIN    0x00000100
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_FOREIGN_KEY
 | 
						|
#  define FKEY       0
 | 
						|
#else
 | 
						|
#  define FKEY       0x00000200
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_PRAGMA
 | 
						|
#  define PRAGMA     0
 | 
						|
#else
 | 
						|
#  define PRAGMA     0x00000400
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_REINDEX
 | 
						|
#  define REINDEX    0
 | 
						|
#else
 | 
						|
#  define REINDEX    0x00000800
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_SUBQUERY
 | 
						|
#  define SUBQUERY   0
 | 
						|
#else
 | 
						|
#  define SUBQUERY   0x00001000
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_TRIGGER
 | 
						|
#  define TRIGGER    0
 | 
						|
#else
 | 
						|
#  define TRIGGER    0x00002000
 | 
						|
#endif
 | 
						|
#if defined(SQLITE_OMIT_AUTOVACUUM) && \
 | 
						|
    (defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH))
 | 
						|
#  define VACUUM     0
 | 
						|
#else
 | 
						|
#  define VACUUM     0x00004000
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_VIEW
 | 
						|
#  define VIEW       0
 | 
						|
#else
 | 
						|
#  define VIEW       0x00008000
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_VIRTUALTABLE
 | 
						|
#  define VTAB       0
 | 
						|
#else
 | 
						|
#  define VTAB       0x00010000
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_AUTOVACUUM
 | 
						|
#  define AUTOVACUUM 0
 | 
						|
#else
 | 
						|
#  define AUTOVACUUM 0x00020000
 | 
						|
#endif
 | 
						|
#ifdef SQLITE_OMIT_CTE
 | 
						|
#  define CTE        0
 | 
						|
#else
 | 
						|
#  define CTE        0x00040000
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
** These are the keywords
 | 
						|
*/
 | 
						|
static Keyword aKeywordTable[] = {
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "ABORT",            "TK_ABORT",        CONFLICT|TRIGGER       },
 | 
						|
#endif
 | 
						|
  { "ACTION",           "TK_ACTION",       FKEY                   },
 | 
						|
  { "ADD",              "TK_ADD",          ALTER                  },
 | 
						|
  { "AFTER",            "TK_AFTER",        TRIGGER                },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "AGAINST",          "TK_AGAINST",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "ALL",              "TK_ALL",          ALWAYS                 },
 | 
						|
  { "ALTER",            "TK_ALTER",        ALTER                  },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "ALGORITHM",        "TK_ALGORITHM",    ANALYZE                },
 | 
						|
#endif
 | 
						|
  { "ANALYZE",          "TK_ANALYZE",      ANALYZE                },
 | 
						|
  { "AND",              "TK_AND",          ALWAYS                 },
 | 
						|
  { "AS",               "TK_AS",           ALWAYS                 },
 | 
						|
  { "ASC",              "TK_ASC",          ALWAYS                 },
 | 
						|
  { "ATTACH",           "TK_ATTACH",       ATTACH                 },
 | 
						|
  { "AUTOINCREMENT",    "TK_AUTOINCR",     AUTOINCR               },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "AUTO_INCREMENT",   "TK_AUTOINCR",     AUTOINCR               },
 | 
						|
#endif
 | 
						|
  { "BEFORE",           "TK_BEFORE",       TRIGGER                },
 | 
						|
  { "BEGIN",            "TK_BEGIN",        ALWAYS                 },
 | 
						|
  { "BETWEEN",          "TK_BETWEEN",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "BINARY",           "TK_BINARY",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "BY",               "TK_BY",           ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "CALL",             "TK_CALL",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "CASCADE",          "TK_CASCADE",      FKEY                   },
 | 
						|
  { "CASE",             "TK_CASE",         ALWAYS                 },
 | 
						|
  { "CAST",             "TK_CAST",         CAST                   },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "CHARACTER",        "TK_CHARACTER",    ALWAYS                 },
 | 
						|
  { "CHARSET",          "TK_CHARSET",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "CHECK",            "TK_CHECK",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "CLOSE",            "TK_CLOSE",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "COLLATE",          "TK_COLLATE",      ALWAYS                 },
 | 
						|
  { "COLUMN",           "TK_COLUMNKW",     ALTER                  },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "COLUMNS",          "TK_COLUMNS",      ALWAYS                 },
 | 
						|
  { "COMMENT",          "TK_COMMENT",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "COMMIT",           "TK_COMMIT",       ALWAYS                 },
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "CONFLICT",         "TK_CONFLICT",     CONFLICT               },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "CONCURRENT",       "TK_CONCURRENT",   ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "CONSTRAINT",       "TK_CONSTRAINT",   ALWAYS                 },
 | 
						|
  { "CREATE",           "TK_CREATE",       ALWAYS                 },
 | 
						|
  { "CROSS",            "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "CURRENT",          "TK_CURRENT",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "CURRENT_DATE",     "TK_CTIME_KW",     ALWAYS                 },
 | 
						|
  { "CURRENT_TIME",     "TK_CTIME_KW",     ALWAYS                 },
 | 
						|
  { "CURRENT_TIMESTAMP","TK_CTIME_KW",     ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DATA",             "TK_DATA",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "DATABASE",         "TK_DATABASE",     ATTACH                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DATABASES",        "TK_DATABASES_KW", ALWAYS                 },
 | 
						|
  { "DEALLOCATE",       "TK_DEALLOCATE",   ALWAYS                 },
 | 
						|
  { "DECLARE",          "TK_DECLARE",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "DEFAULT",          "TK_DEFAULT",      ALWAYS                 },
 | 
						|
  { "DEFERRED",         "TK_DEFERRED",     ALWAYS                 },
 | 
						|
  { "DEFERRABLE",       "TK_DEFERRABLE",   FKEY                   },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DELAYED",          "TK_DELAYED",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "DELETE",           "TK_DELETE",       ALWAYS                 },
 | 
						|
  { "DESC",             "TK_DESC",         ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DESCRIBE",         "TK_EXPLAIN" ,     ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "DETACH",           "TK_DETACH",       ATTACH                 },
 | 
						|
  { "DISTINCT",         "TK_DISTINCT",     ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DISTINCTROW",      "TK_DISTINCT",     ALWAYS                 },
 | 
						|
  { "DO",               "TK_DO",           ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "DROP",             "TK_DROP",         ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "DUMPFILE",         "TK_DUMPFILE",     ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "END",              "TK_END",          ALWAYS                 },
 | 
						|
  { "EACH",             "TK_EACH",         TRIGGER                },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "ENABLE",           "TK_ENABLE",       ALWAYS                 },
 | 
						|
  { "ENGINE",           "TK_ENGINE",       ALWAYS                 },
 | 
						|
  { "ENUM",             "TK_ENUM",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "ELSE",             "TK_ELSE",         ALWAYS                 },
 | 
						|
  { "ESCAPE",           "TK_ESCAPE",       ALWAYS                 },
 | 
						|
  { "EXCEPT",           "TK_EXCEPT",       COMPOUND               },
 | 
						|
  { "EXCLUSIVE",        "TK_EXCLUSIVE",    ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "EXECUTE",          "TK_EXECUTE",      ALWAYS                 },
 | 
						|
  { "EXCLUDE",          "TK_EXCLUDE",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "EXISTS",           "TK_EXISTS",       ALWAYS                 },
 | 
						|
  { "EXPLAIN",          "TK_EXPLAIN",      EXPLAIN                },
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "FAIL",             "TK_FAIL",         CONFLICT|TRIGGER       },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "FIRST",            "TK_FIRST",        ALWAYS                 },
 | 
						|
  { "FLUSH",            "TK_FLUSH",        ALWAYS                 },
 | 
						|
  { "FOLLOWING",        "TK_FOLLOWING",    ALWAYS                 },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "FOR",              "TK_FOR",          ALWAYS                 },
 | 
						|
#else
 | 
						|
  { "FOR",              "TK_FOR",          TRIGGER                },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "FORCE",            "TK_FORCE",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "FOREIGN",          "TK_FOREIGN",      FKEY                   },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "FORMAT",           "TK_FORMAT",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "FROM",             "TK_FROM",         ALWAYS                 },
 | 
						|
  { "FULL",             "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "FULLTEXT",         "TK_FULLTEXT",     ALWAYS                 },
 | 
						|
  { "FUNCTION",         "TK_FUNCTION_KW",  ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "GLOB",             "TK_LIKE_KW",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "GLOBAL",           "TK_GLOBAL",       ALWAYS                 },
 | 
						|
  { "GRANT",            "TK_GRANT",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "GROUP",            "TK_GROUP",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "HANDLER",          "TK_HANDLER",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "HAVING",           "TK_HAVING",       ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "HIGH_PRIORITY",    "TK_HIGH_PRIORITY",ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "IF",               "TK_IF",           ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "IGNORE",           "TK_IGNORE",       ALWAYS                 },
 | 
						|
#else
 | 
						|
  { "IGNORE",           "TK_IGNORE",       CONFLICT|TRIGGER       },
 | 
						|
#endif
 | 
						|
  { "IMMEDIATE",        "TK_IMMEDIATE",    ALWAYS                 },
 | 
						|
  { "IN",               "TK_IN",           ALWAYS                 },
 | 
						|
  { "INDEX",            "TK_INDEX",        ALWAYS                 },
 | 
						|
  { "INDEXED",          "TK_INDEXED",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "INDEXES",          "TK_INDEXES",      ALWAYS                 },
 | 
						|
  { "INFILE",           "TK_INFILE",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "INITIALLY",        "TK_INITIALLY",    FKEY                   },
 | 
						|
  { "INNER",            "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
  { "INSERT",           "TK_INSERT",       ALWAYS                 },
 | 
						|
  { "INSTEAD",          "TK_INSTEAD",      TRIGGER                },
 | 
						|
  { "INTERSECT",        "TK_INTERSECT",    COMPOUND               },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "INTERVAL",         "TK_INTERVAL",     ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "INTO",             "TK_INTO",         ALWAYS                 },
 | 
						|
  { "IS",               "TK_IS",           ALWAYS                 },
 | 
						|
  { "ISNULL",           "TK_ISNULL",       ALWAYS                 },
 | 
						|
  { "JOIN",             "TK_JOIN",         ALWAYS                 },
 | 
						|
  { "KEY",              "TK_KEY",          ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "KEYS",             "TK_KEYS",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "LEFT",             "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
  { "LIKE",             "TK_LIKE_KW",      ALWAYS                 },
 | 
						|
  { "LIMIT",            "TK_LIMIT",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "LOAD",             "TK_LOAD",         ALWAYS                 },
 | 
						|
  { "LOCAL",            "TK_LOCAL",        ALWAYS                 },
 | 
						|
  { "LOCK",             "TK_LOCK",         ALWAYS                 },
 | 
						|
  { "LOW_PRIORITY",     "TK_LOW_PRIORITY", ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "MATCH",            "TK_MATCH",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "MASTER",           "TK_MASTER",       ALWAYS                 },
 | 
						|
  { "MERGE",            "TK_MERGE",        ALWAYS                 },
 | 
						|
  { "NAMES",            "TK_NAMES",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "NATURAL",          "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "NEXT",             "TK_NEXT",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "NO",               "TK_NO",           FKEY                   },
 | 
						|
  { "NOT",              "TK_NOT",          ALWAYS                 },
 | 
						|
  { "NOTNULL",          "TK_NOTNULL",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "NO_WRITE_TO_BINLOG","TK_NO_WRITE_TO_BINLOG",ALWAYS           },
 | 
						|
#endif
 | 
						|
  { "NULL",             "TK_NULL",         ALWAYS                 },
 | 
						|
  { "OF",               "TK_OF",           ALWAYS                 },
 | 
						|
  { "OFFSET",           "TK_OFFSET",       ALWAYS                 },
 | 
						|
  { "ON",               "TK_ON",           ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "OPEN",             "TK_OPEN",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "OR",               "TK_OR",           ALWAYS                 },
 | 
						|
  { "ORDER",            "TK_ORDER",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "OTHERS",           "TK_OTHERS",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "OUTER",            "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "OUTFILE",          "TK_OUTFILE",      ALWAYS                 },
 | 
						|
  { "OVER",             "TK_OVER",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "PARTITION",        "TK_PARTITION",    ALWAYS                 },
 | 
						|
  { "PERSISTENT",       "TK_PERSISTENT",   ALWAYS                 },
 | 
						|
#endif
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "PLAN",             "TK_PLAN",         EXPLAIN                },
 | 
						|
#endif
 | 
						|
  { "PRAGMA",           "TK_PRAGMA",       PRAGMA                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "PRECEDING",        "TK_PRECEDING",    ALWAYS                 },
 | 
						|
  { "PREPARE",          "TK_PREPARE",      ALWAYS                 },
 | 
						|
  { "PREVIOUS",         "TK_PREVIOUS",     ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "PRIMARY",          "TK_PRIMARY",      ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "PROCEDURE",        "TK_FUNCTION_KW",  ALWAYS                 },
 | 
						|
#endif
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "QUERY",            "TK_QUERY",        EXPLAIN                },
 | 
						|
#endif
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "QUICK",            "TK_QUICK",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "RAISE",            "TK_RAISE",        TRIGGER                },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "RANGE",            "TK_RANGE",        ALWAYS                 },
 | 
						|
  { "READ",             "TK_READ",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "RECURSIVE",        "TK_RECURSIVE",    CTE                    },
 | 
						|
  { "REFERENCES",       "TK_REFERENCES",   FKEY                   },
 | 
						|
  { "REGEXP",           "TK_LIKE_KW",      ALWAYS                 },
 | 
						|
  { "REINDEX",          "TK_REINDEX",      REINDEX                },
 | 
						|
  { "RELEASE",          "TK_RELEASE",      ALWAYS                 },
 | 
						|
  { "RENAME",           "TK_RENAME",       ALTER                  },
 | 
						|
  { "REPLACE",          "TK_REPLACE",      CONFLICT               },
 | 
						|
  { "RESTRICT",         "TK_RESTRICT",     FKEY                   },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "REVOKE",           "TK_REVOKE",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "RIGHT",            "TK_JOIN_KW",      ALWAYS                 },
 | 
						|
  { "ROLLBACK",         "TK_ROLLBACK",     ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "ROLLUP",           "TK_ROLLUP",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "ROW",              "TK_ROW",          TRIGGER                },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "ROWS",             "TK_ROWS",         ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "SAVEPOINT",        "TK_SAVEPOINT",    ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "SCHEMAS",          "TK_DATABASES_KW", ALWAYS                 },
 | 
						|
  { "SEQUENCE",         "TK_SEQUENCE",     ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "SELECT",           "TK_SELECT",       ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "SESSION",          "TK_SESSION",      ALWAYS                 },
 | 
						|
  { "SEPARATOR",        "TK_SEPARATOR",    ALWAYS                 },
 | 
						|
  { "SHOW",             "TK_SHOW",         ALWAYS                 },
 | 
						|
  { "SLAVE",            "TK_SLAVE",        ALWAYS                 },
 | 
						|
  { "SPATIAL",          "TK_SPATIAL",      ALWAYS                 },
 | 
						|
  { "SQL_BIG_RESULT",   "TK_SELECT_OPTIONS_KW", ALWAYS            },
 | 
						|
  { "SQL_BUFFER_RESULT","TK_SELECT_OPTIONS_KW", ALWAYS            },
 | 
						|
  { "SQL_CACHE",        "TK_SELECT_OPTIONS_KW", ALWAYS            },
 | 
						|
  { "SQL_CALC_FOUND_ROWS","TK_SELECT_OPTIONS_KW", ALWAYS          },
 | 
						|
  { "SQL_NO_CACHE",     "TK_SELECT_OPTIONS_KW", ALWAYS            },
 | 
						|
  { "SQL_SMALL_RESULT", "TK_SELECT_OPTIONS_KW", ALWAYS            },
 | 
						|
#endif
 | 
						|
  { "SET",              "TK_SET",          ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "START",            "TK_START",        ALWAYS                 },
 | 
						|
  { "STATEMENT",        "TK_STATEMENT",    ALWAYS                 },
 | 
						|
  { "STATUS",           "TK_STATUS",       ALWAYS                 },
 | 
						|
  { "STRAIGHT_JOIN",    "TK_STRAIGHT_JOIN",ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "TABLE",            "TK_TABLE",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "TABLES",           "TK_TABLES",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "TEMP",             "TK_TEMP",         ALWAYS                 },
 | 
						|
  { "TEMPORARY",        "TK_TEMP",         ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "TEMPTABLE",        "TK_TEMPTABLE",    ANALYZE                },
 | 
						|
#endif
 | 
						|
  { "THEN",             "TK_THEN",         ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "TIES",             "TK_TIES",         ANALYZE                },
 | 
						|
#endif
 | 
						|
  { "TO",               "TK_TO",           ALWAYS                 },
 | 
						|
  { "TRANSACTION",      "TK_TRANSACTION",  ALWAYS                 },
 | 
						|
  { "TRIGGER",          "TK_TRIGGER",      TRIGGER                },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "TRUNCATE",         "TK_TRUNCATE",     ALWAYS                 },
 | 
						|
  { "UNBOUNDED",        "TK_UNBOUNDED",    ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "UNION",            "TK_UNION",        COMPOUND               },
 | 
						|
  { "UNSIGNED",         "TK_UNSIGNED",     ALWAYS                 },
 | 
						|
  { "UNIQUE",           "TK_UNIQUE",       ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "UNLOCK",           "TK_UNLOCK",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "UPDATE",           "TK_UPDATE",       ALWAYS                 },
 | 
						|
  { "USE",              "TK_USE",          ALWAYS                 },
 | 
						|
  { "USING",            "TK_USING",        ALWAYS                 },
 | 
						|
  { "VACUUM",           "TK_VACUUM",       VACUUM                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "VALUE",            "TK_VALUE",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "VALUES",           "TK_VALUES",       ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "VARIABLES",        "TK_VARIABLES",    ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "VIEW",             "TK_VIEW",         VIEW                   },
 | 
						|
  { "VIRTUAL",          "TK_VIRTUAL",      VTAB                   },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "WARNINGS",         "TK_WARNINGS",     ALWAYS                 },
 | 
						|
  { "WINDOW",           "TK_WINDOW",       ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "WITH",             "TK_WITH",         CTE                    },
 | 
						|
#ifndef MAXSCALE
 | 
						|
  { "WITHOUT",          "TK_WITHOUT",      ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "WHEN",             "TK_WHEN",         ALWAYS                 },
 | 
						|
  { "WHERE",            "TK_WHERE",        ALWAYS                 },
 | 
						|
#ifdef MAXSCALE
 | 
						|
  { "WORK",             "TK_WORK",         ALWAYS                 },
 | 
						|
  { "WRITE",            "TK_WRITE",        ALWAYS                 },
 | 
						|
#endif
 | 
						|
  { "ZEROFILL",         "TK_ZEROFILL",     ALWAYS                 },
 | 
						|
};
 | 
						|
 | 
						|
/* Number of keywords */
 | 
						|
static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
 | 
						|
 | 
						|
/* Map all alphabetic characters into lower-case for hashing.  This is
 | 
						|
** only valid for alphabetics.  In particular it does not work for '_'
 | 
						|
** and so the hash cannot be on a keyword position that might be an '_'.
 | 
						|
*/
 | 
						|
#define charMap(X)   (0x20|(X))
 | 
						|
 | 
						|
/*
 | 
						|
** Comparision function for two Keyword records
 | 
						|
*/
 | 
						|
static int keywordCompare1(const void *a, const void *b){
 | 
						|
  const Keyword *pA = (Keyword*)a;
 | 
						|
  const Keyword *pB = (Keyword*)b;
 | 
						|
  int n = pA->len - pB->len;
 | 
						|
  if( n==0 ){
 | 
						|
    n = strcmp(pA->zName, pB->zName);
 | 
						|
  }
 | 
						|
  assert( n!=0 );
 | 
						|
  return n;
 | 
						|
}
 | 
						|
static int keywordCompare2(const void *a, const void *b){
 | 
						|
  const Keyword *pA = (Keyword*)a;
 | 
						|
  const Keyword *pB = (Keyword*)b;
 | 
						|
  int n = pB->longestSuffix - pA->longestSuffix;
 | 
						|
  if( n==0 ){
 | 
						|
    n = strcmp(pA->zName, pB->zName);
 | 
						|
  }
 | 
						|
  assert( n!=0 );
 | 
						|
  return n;
 | 
						|
}
 | 
						|
static int keywordCompare3(const void *a, const void *b){
 | 
						|
  const Keyword *pA = (Keyword*)a;
 | 
						|
  const Keyword *pB = (Keyword*)b;
 | 
						|
  int n = pA->offset - pB->offset;
 | 
						|
  if( n==0 ) n = pB->id - pA->id;
 | 
						|
  assert( n!=0 );
 | 
						|
  return n;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Return a KeywordTable entry with the given id
 | 
						|
*/
 | 
						|
static Keyword *findById(int id){
 | 
						|
  int i;
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    if( aKeywordTable[i].id==id ) break;
 | 
						|
  }
 | 
						|
  return &aKeywordTable[i];
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** This routine does the work.  The generated code is printed on standard
 | 
						|
** output.
 | 
						|
*/
 | 
						|
int main(int argc, char **argv){
 | 
						|
  int i, j, k, h;
 | 
						|
  int bestSize, bestCount;
 | 
						|
  int count;
 | 
						|
  int nChar;
 | 
						|
  int totalLen = 0;
 | 
						|
  int aHash[1000];  /* 1000 is much bigger than nKeyword */
 | 
						|
  char zText[2000];
 | 
						|
 | 
						|
  /* Remove entries from the list of keywords that have mask==0 */
 | 
						|
  for(i=j=0; i<nKeyword; i++){
 | 
						|
    if( aKeywordTable[i].mask==0 ) continue;
 | 
						|
    if( j<i ){
 | 
						|
      aKeywordTable[j] = aKeywordTable[i];
 | 
						|
    }
 | 
						|
    j++;
 | 
						|
  }
 | 
						|
  nKeyword = j;
 | 
						|
 | 
						|
  /* Fill in the lengths of strings and hashes for all entries. */
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    p->len = (int)strlen(p->zName);
 | 
						|
    assert( p->len<sizeof(p->zOrigName) );
 | 
						|
    memcpy(p->zOrigName, p->zName, p->len+1);
 | 
						|
    totalLen += p->len;
 | 
						|
    p->hash = (charMap(p->zName[0])*4) ^
 | 
						|
              (charMap(p->zName[p->len-1])*3) ^ (p->len*1);
 | 
						|
    p->id = i+1;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Sort the table from shortest to longest keyword */
 | 
						|
  qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1);
 | 
						|
 | 
						|
  /* Look for short keywords embedded in longer keywords */
 | 
						|
  for(i=nKeyword-2; i>=0; i--){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    for(j=nKeyword-1; j>i && p->substrId==0; j--){
 | 
						|
      Keyword *pOther = &aKeywordTable[j];
 | 
						|
      if( pOther->substrId ) continue;
 | 
						|
      if( pOther->len<=p->len ) continue;
 | 
						|
      for(k=0; k<=pOther->len-p->len; k++){
 | 
						|
        if( memcmp(p->zName, &pOther->zName[k], p->len)==0 ){
 | 
						|
          p->substrId = pOther->id;
 | 
						|
          p->substrOffset = k;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Compute the longestSuffix value for every word */
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    if( p->substrId ) continue;
 | 
						|
    for(j=0; j<nKeyword; j++){
 | 
						|
      Keyword *pOther;
 | 
						|
      if( j==i ) continue;
 | 
						|
      pOther = &aKeywordTable[j];
 | 
						|
      if( pOther->substrId ) continue;
 | 
						|
      for(k=p->longestSuffix+1; k<p->len && k<pOther->len; k++){
 | 
						|
        if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
 | 
						|
          p->longestSuffix = k;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Sort the table into reverse order by length */
 | 
						|
  qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare2);
 | 
						|
 | 
						|
  /* Fill in the offset for all entries */
 | 
						|
  nChar = 0;
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    if( p->offset>0 || p->substrId ) continue;
 | 
						|
    p->offset = nChar;
 | 
						|
    nChar += p->len;
 | 
						|
    for(k=p->len-1; k>=1; k--){
 | 
						|
      for(j=i+1; j<nKeyword; j++){
 | 
						|
        Keyword *pOther = &aKeywordTable[j];
 | 
						|
        if( pOther->offset>0 || pOther->substrId ) continue;
 | 
						|
        if( pOther->len<=k ) continue;
 | 
						|
        if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
 | 
						|
          p = pOther;
 | 
						|
          p->offset = nChar - k;
 | 
						|
          nChar = p->offset + p->len;
 | 
						|
          p->zName += k;
 | 
						|
          p->len -= k;
 | 
						|
          p->prefix = k;
 | 
						|
          j = i;
 | 
						|
          k = p->len;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    if( p->substrId ){
 | 
						|
      p->offset = findById(p->substrId)->offset + p->substrOffset;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Sort the table by offset */
 | 
						|
  qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3);
 | 
						|
 | 
						|
  /* Figure out how big to make the hash table in order to minimize the
 | 
						|
  ** number of collisions */
 | 
						|
  bestSize = nKeyword;
 | 
						|
  bestCount = nKeyword*nKeyword;
 | 
						|
  for(i=nKeyword/2; i<=2*nKeyword; i++){
 | 
						|
    for(j=0; j<i; j++) aHash[j] = 0;
 | 
						|
    for(j=0; j<nKeyword; j++){
 | 
						|
      h = aKeywordTable[j].hash % i;
 | 
						|
      aHash[h] *= 2;
 | 
						|
      aHash[h]++;
 | 
						|
    }
 | 
						|
    for(j=count=0; j<i; j++) count += aHash[j];
 | 
						|
    if( count<bestCount ){
 | 
						|
      bestCount = count;
 | 
						|
      bestSize = i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* Compute the hash */
 | 
						|
  for(i=0; i<bestSize; i++) aHash[i] = 0;
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    h = aKeywordTable[i].hash % bestSize;
 | 
						|
    aKeywordTable[i].iNext = aHash[h];
 | 
						|
    aHash[h] = i+1;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Begin generating code */
 | 
						|
  printf("%s", zHdr);
 | 
						|
  printf("/* Hash score: %d */\n", bestCount);
 | 
						|
  printf("static int keywordCode(const char *z, int n, int *pType){\n");
 | 
						|
  printf("  /* zText[] encodes %d bytes of keywords in %d bytes */\n",
 | 
						|
          totalLen + nKeyword, nChar+1 );
 | 
						|
  for(i=j=k=0; i<nKeyword; i++){
 | 
						|
    Keyword *p = &aKeywordTable[i];
 | 
						|
    if( p->substrId ) continue;
 | 
						|
    memcpy(&zText[k], p->zName, p->len);
 | 
						|
    k += p->len;
 | 
						|
    if( j+p->len>70 ){
 | 
						|
      printf("%*s */\n", 74-j, "");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
    if( j==0 ){
 | 
						|
      printf("  /*   ");
 | 
						|
      j = 8;
 | 
						|
    }
 | 
						|
    printf("%s", p->zName);
 | 
						|
    j += p->len;
 | 
						|
  }
 | 
						|
  if( j>0 ){
 | 
						|
    printf("%*s */\n", 74-j, "");
 | 
						|
  }
 | 
						|
  printf("  static const char zText[%d] = {\n", nChar);
 | 
						|
  zText[nChar] = 0;
 | 
						|
  for(i=j=0; i<k; i++){
 | 
						|
    if( j==0 ){
 | 
						|
      printf("    ");
 | 
						|
    }
 | 
						|
    if( zText[i]==0 ){
 | 
						|
      printf("0");
 | 
						|
    }else{
 | 
						|
      printf("'%c',", zText[i]);
 | 
						|
    }
 | 
						|
    j += 4;
 | 
						|
    if( j>68 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if( j>0 ) printf("\n");
 | 
						|
  printf("  };\n");
 | 
						|
 | 
						|
  printf("  static const unsigned char aHash[%d] = {\n", bestSize);
 | 
						|
  for(i=j=0; i<bestSize; i++){
 | 
						|
    if( j==0 ) printf("    ");
 | 
						|
    printf(" %3d,", aHash[i]);
 | 
						|
    j++;
 | 
						|
    if( j>12 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  printf("%s  };\n", j==0 ? "" : "\n");    
 | 
						|
 | 
						|
  printf("  static const unsigned char aNext[%d] = {\n", nKeyword);
 | 
						|
  for(i=j=0; i<nKeyword; i++){
 | 
						|
    if( j==0 ) printf("    ");
 | 
						|
    printf(" %3d,", aKeywordTable[i].iNext);
 | 
						|
    j++;
 | 
						|
    if( j>12 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  printf("%s  };\n", j==0 ? "" : "\n");    
 | 
						|
 | 
						|
  printf("  static const unsigned char aLen[%d] = {\n", nKeyword);
 | 
						|
  for(i=j=0; i<nKeyword; i++){
 | 
						|
    if( j==0 ) printf("    ");
 | 
						|
    printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
 | 
						|
    j++;
 | 
						|
    if( j>12 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  printf("%s  };\n", j==0 ? "" : "\n");    
 | 
						|
 | 
						|
  printf("  static const unsigned short int aOffset[%d] = {\n", nKeyword);
 | 
						|
  for(i=j=0; i<nKeyword; i++){
 | 
						|
    if( j==0 ) printf("    ");
 | 
						|
    printf(" %3d,", aKeywordTable[i].offset);
 | 
						|
    j++;
 | 
						|
    if( j>12 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  printf("%s  };\n", j==0 ? "" : "\n");
 | 
						|
 | 
						|
  printf("  static const unsigned char aCode[%d] = {\n", nKeyword);
 | 
						|
  for(i=j=0; i<nKeyword; i++){
 | 
						|
    char *zToken = aKeywordTable[i].zTokenType;
 | 
						|
    if( j==0 ) printf("    ");
 | 
						|
    printf("%s,%*s", zToken, (int)(14-strlen(zToken)), "");
 | 
						|
    j++;
 | 
						|
    if( j>=5 ){
 | 
						|
      printf("\n");
 | 
						|
      j = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  printf("%s  };\n", j==0 ? "" : "\n");
 | 
						|
 | 
						|
  printf("  int i, j;\n");
 | 
						|
  printf("  const char *zKW;\n");
 | 
						|
  printf("  if( n>=2 ){\n");
 | 
						|
  printf("    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n",
 | 
						|
          bestSize);
 | 
						|
  printf("    for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){\n");
 | 
						|
  printf("      if( aLen[i]!=n ) continue;\n");
 | 
						|
  printf("      j = 0;\n");
 | 
						|
  printf("      zKW = &zText[aOffset[i]];\n");
 | 
						|
  printf("#ifdef SQLITE_ASCII\n");
 | 
						|
  printf("      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }\n");
 | 
						|
  printf("#endif\n");
 | 
						|
  printf("#ifdef SQLITE_EBCDIC\n");
 | 
						|
  printf("      while( j<n && toupper(z[j])==zKW[j] ){ j++; }\n");
 | 
						|
  printf("#endif\n");
 | 
						|
  printf("      if( j<n ) continue;\n");
 | 
						|
  for(i=0; i<nKeyword; i++){
 | 
						|
    printf("      testcase( i==%d ); /* %s */\n",
 | 
						|
           i, aKeywordTable[i].zOrigName);
 | 
						|
  }
 | 
						|
  printf("      *pType = aCode[i];\n");
 | 
						|
  printf("      break;\n");
 | 
						|
  printf("    }\n");
 | 
						|
  printf("  }\n");
 | 
						|
  printf("  return n;\n");
 | 
						|
  printf("}\n");
 | 
						|
  printf("int sqlite3KeywordCode(const unsigned char *z, int n){\n");
 | 
						|
  printf("  int id = TK_ID;\n");
 | 
						|
  printf("  keywordCode((char*)z, n, &id);\n");
 | 
						|
  printf("  return id;\n");
 | 
						|
  printf("}\n");
 | 
						|
  printf("#define SQLITE_N_KEYWORD %d\n", nKeyword);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 |