/ Check-in [007aec11]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The makefile now runs mkkeywordhash.c. Keywords that are unused are omitted from the keyword hash table. (CVS 2045)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:007aec11333432e08d1091b728773011e9078bc3
User & Date: drh 2004-11-03 03:59:57
Context
2004-11-03
08:44
Auto-vacuum bug: Correctly manipulate page cache hash-table entries in sqlite3pager_movepage(). (CVS 2046) check-in: 719c1b79 user: danielk1977 tags: trunk
03:59
The makefile now runs mkkeywordhash.c. Keywords that are unused are omitted from the keyword hash table. (CVS 2045) check-in: 007aec11 user: drh tags: trunk
03:52
Auto-vacuum bugfix: Do not attempt to move a pointer-map page during auto-vacuum. (CVS 2044) check-in: bd50fbb5 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

72
73
74
75
76
77
78


79
80
81
82
83
84
85
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
328
329
330
331
332
333
334
335
336




337
338
339
340
341
342
343
...
550
551
552
553
554
555
556
557

558
559
560
561
562
563
564
# default to file, 2 to default to memory, and 3 to force temporary
# tables to always be in memory.
#
TEMP_STORE = -DTEMP_STORE=@TEMP_STORE@

# You should not have to change anything below this line
###############################################################################



# Object files for the SQLite library.
#
LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo delete.lo \
         expr.lo func.lo hash.lo insert.lo \
         main.lo opcodes.lo os_mac.lo os_unix.lo os_win.lo \
         pager.lo parse.lo pragma.lo printf.lo random.lo \
................................................................................

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) $(VDBEHDR) 
	rm -rf tsrc
	mkdir -p tsrc
	cp $(SRC) $(VDBEHDR) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	cp parse.c opcodes.c tsrc
	cp $(TOP)/sqlite3.def tsrc

# Rules to build the LEMON compiler generator
#
lemon@BUILD_EXEEXT@:	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .


# Rules to build individual files
#
attach.lo:	$(TOP)/src/attach.c $(HDR)
................................................................................
	$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_win.c

parse.lo:	parse.c $(HDR)
	$(LTCOMPILE) -c parse.c

parse.h:	parse.c

parse.c:	$(TOP)/src/parse.y lemon@BUILD_EXEEXT@
	cp $(TOP)/src/parse.y .
	./lemon $(OPTS) parse.y

pragma.lo:	$(TOP)/src/pragma.c $(HDR)
	$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/pragma.c

printf.lo:	$(TOP)/src/printf.c $(HDR)
................................................................................

table.lo:	$(TOP)/src/table.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/table.c

tclsqlite.lo:	$(TOP)/src/tclsqlite.c $(HDR)
	$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c

tokenize.lo:	$(TOP)/src/tokenize.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/tokenize.c





trigger.lo:	$(TOP)/src/trigger.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/trigger.c

update.lo:	$(TOP)/src/update.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/update.c

................................................................................
	$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig; 
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig; 

clean:	
	rm -f *.lo *.la *.o sqlite3@TARGET_EXEEXT@ libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps 
	rm -f lemon@BUILD_EXEEXT@ lempar.c parse.* sqlite*.tar.gz

	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -f testfixture@TARGET_EXEEXT@ test.db
	rm -rf doc
	rm -f common.tcl
	rm -f sqlite3.dll sqlite3.lib








>
>







 







|




|




|







 







|







 







|

>
>
>
>







 







|
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# default to file, 2 to default to memory, and 3 to force temporary
# tables to always be in memory.
#
TEMP_STORE = -DTEMP_STORE=@TEMP_STORE@

# You should not have to change anything below this line
###############################################################################

BEXE = @BUILD_EXEEXT@

# Object files for the SQLite library.
#
LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo delete.lo \
         expr.lo func.lo hash.lo insert.lo \
         main.lo opcodes.lo os_mac.lo os_unix.lo os_win.lo \
         pager.lo parse.lo pragma.lo printf.lo random.lo \
................................................................................

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) parse.c opcodes.c keywordhash.c $(VDBEHDR) 
	rm -rf tsrc
	mkdir -p tsrc
	cp $(SRC) $(VDBEHDR) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	cp parse.c opcodes.c keywordhash.c tsrc
	cp $(TOP)/sqlite3.def tsrc

# Rules to build the LEMON compiler generator
#
lemon$(BEXE):	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .


# Rules to build individual files
#
attach.lo:	$(TOP)/src/attach.c $(HDR)
................................................................................
	$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_win.c

parse.lo:	parse.c $(HDR)
	$(LTCOMPILE) -c parse.c

parse.h:	parse.c

parse.c:	$(TOP)/src/parse.y lemon$(BEXE)
	cp $(TOP)/src/parse.y .
	./lemon $(OPTS) parse.y

pragma.lo:	$(TOP)/src/pragma.c $(HDR)
	$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/pragma.c

printf.lo:	$(TOP)/src/printf.c $(HDR)
................................................................................

table.lo:	$(TOP)/src/table.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/table.c

tclsqlite.lo:	$(TOP)/src/tclsqlite.c $(HDR)
	$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c

tokenize.lo:	$(TOP)/src/tokenize.c keywordhash.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/tokenize.c

keywordhash.c:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash$(BEXE) $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash$(BEXE) >keywordhash.c

trigger.lo:	$(TOP)/src/trigger.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/trigger.c

update.lo:	$(TOP)/src/update.c $(HDR)
	$(LTCOMPILE) -c $(TOP)/src/update.c

................................................................................
	$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig; 
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig; 

clean:	
	rm -f *.lo *.la *.o sqlite3@TARGET_EXEEXT@ libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps 
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.c
	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -f testfixture@TARGET_EXEEXT@ test.db
	rm -rf doc
	rm -f common.tcl
	rm -f sqlite3.dll sqlite3.lib

Changes to main.mk.

177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
298
299
300
301
302
303
304
305
306




307
308
309
310
311
312
313
...
523
524
525
526
527
528
529
530
531
532
533

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) $(VDBEHDR) opcodes.c
	rm -rf tsrc
	mkdir tsrc
	cp $(SRC) $(VDBEHDR) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	cp parse.c opcodes.c tsrc
	cp $(TOP)/sqlite3.def tsrc

# Rules to build the LEMON compiler generator
#
lemon:	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .
................................................................................

table.o:	$(TOP)/src/table.c $(HDR)
	$(TCCX) -c $(TOP)/src/table.c

tclsqlite.o:	$(TOP)/src/tclsqlite.c $(HDR)
	$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c

tokenize.o:	$(TOP)/src/tokenize.c $(HDR)
	$(TCCX) -c $(TOP)/src/tokenize.c





trigger.o:	$(TOP)/src/trigger.c $(HDR)
	$(TCCX) -c $(TOP)/src/trigger.c

update.o:	$(TOP)/src/update.c $(HDR)
	$(TCCX) -c $(TOP)/src/update.c

................................................................................
install:	sqlite3 libsqlite3.a sqlite3.h
	mv sqlite3 /usr/bin
	mv libsqlite3.a /usr/lib
	mv sqlite3.h /usr/include

clean:	
	rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
	rm -f lemon lempar.c parse.* sqlite*.tar.gz
	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -rf tsrc







|




|







 







|

>
>
>
>







 







|



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
...
527
528
529
530
531
532
533
534
535
536
537

# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
target_source:	$(SRC) $(VDBEHDR) opcodes.c keyworkhash.c
	rm -rf tsrc
	mkdir tsrc
	cp $(SRC) $(VDBEHDR) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	cp parse.c opcodes.c keywordhash.c tsrc
	cp $(TOP)/sqlite3.def tsrc

# Rules to build the LEMON compiler generator
#
lemon:	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .
................................................................................

table.o:	$(TOP)/src/table.c $(HDR)
	$(TCCX) -c $(TOP)/src/table.c

tclsqlite.o:	$(TOP)/src/tclsqlite.c $(HDR)
	$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c

tokenize.o:	$(TOP)/src/tokenize.c keywordhash.c $(HDR)
	$(TCCX) -c $(TOP)/src/tokenize.c

keywordhash.c:	$(TOP)/tool/mkkeywordhash.c
	$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
	./mkkeywordhash >keywordhash.c

trigger.o:	$(TOP)/src/trigger.c $(HDR)
	$(TCCX) -c $(TOP)/src/trigger.c

update.o:	$(TOP)/src/update.c $(HDR)
	$(TCCX) -c $(TOP)/src/update.c

................................................................................
install:	sqlite3 libsqlite3.a sqlite3.h
	mv sqlite3 /usr/bin
	mv libsqlite3.a /usr/lib
	mv sqlite3.h /usr/include

clean:	
	rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
	rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.c
	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -rf tsrc

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
146
147
148
149
150
151
152

153
154
155
156
157
158
159
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.145 2004/10/31 02:22:49 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){
................................................................................
  DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
  GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
  OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
  TEMP TRIGGER VACUUM VIEW
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif

  .

// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer.  Keeping the operators together
// causes them to be assigned integer values that are close together,
// which keeps parser tables smaller.
//







|







 







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.146 2004/11/03 03:59:57 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){
................................................................................
  DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
  GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
  OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
  TEMP TRIGGER VACUUM VIEW
%ifdef SQLITE_OMIT_COMPOUND_SELECT
  EXCEPT INTERSECT UNION
%endif
  REINDEX RENAME AUTOINCR CDATE CTIME CTIMESTAMP ALTER
  .

// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer.  Keeping the operators together
// causes them to be assigned integer values that are close together,
// which keeps parser tables smaller.
//

Changes to src/tokenize.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.93 2004/10/31 02:22:49 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>

/*
** 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.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.c, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program was manually cut and pasted
** into this file.  When the set of keywords for SQLite changes, you
** must modify the mkkeywordhash.c program (to add or remove keywords from
** the data tables) then rerun that program to regenerate this function.
*/
int sqlite3KeywordCode(const char *z, int n){
  static const char zText[443] =
    "ABORTABLEFTEMPORARYAFTERAISELECTHENDATABASEACHECKEYANDEFAULTRANSACTION"
    "ATURALIKELSEXCEPTRIGGEREFERENCESTATEMENTATTACHAVINGLOBEFOREIGN"
    "OREPLACEXCLUSIVEXPLAINDEXBEGINITIALLYBETWEENOTNULLIMITBYCASCADE"
    "FERRABLECASECOLLATECOMMITCONFLICTCONSTRAINTERSECTCREATECROSSDEFERRED"
    "ELETEDESCDETACHDISTINCTDROPRAGMATCHFAILFROMFULLGROUPDATEIMMEDIATE"
    "INNERESTRICTINSERTINSTEADINTOFFSETISNULLJOINORDERIGHTOUTEROLLBACK"
    "PRIMARYROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHERE";
  static const unsigned char aHash[154] = {
       0,  26,  82,   0,   0,  91,  90,   0,  27,   0,   0,   0,   0,
       0,   0,  49,   0,  96,  17,   0,   0,   0,   0,   0,   0,   0,
       0,  97,   5,  31,   0,  62,  51,  28,  58,  52,   0,   0,  60,
      61,   0,  12,  41,  50,   0,   0,   0,  36,  63,   0,   0,  15,
       0,   0,   0,  39,   0,  42,   0,   0,   0,   0,  78,   0,  34,
      29,   0,  74,  71,   0,  66,  70,  37,   0,   0,  59,   0,  33,
       0,  53,   0,  54,   0,  55,   0,  83,  72,  67,   0,  24,   0,
       0,  79,  80,  84,   0,   0,   0,   0,   0,   0,   0,  75,   0,
       0,   0,   0,   0,  45,  77,  35,  44,  57,   0,   0,   0,   0,
      20,   2,   0,  38,   0,   3,  46,  93,   0,   0,  40,   0,  94,
       0,  43,  87,  98,   0,   0,   0,   0,   0,  81,   0,   0,   0,
       0,  10,   0,   0,   0,   0,   0,  92,  19,   0,  95,
  };
  static const unsigned char aNext[98] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   7,
       0,  14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   9,   0,
       0,   0,   0,   0,   0,  18,  22,   0,   0,   0,   0,   0,   0,
       0,  23,   0,  16,  21,   8,   0,  32,   0,   0,  30,   0,  48,
       0,   0,   0,   0,   0,   0,   0,  11,   0,   0,   0,   0,   0,
       0,  56,   0,   1,   0,  69,  64,   0,   0,  65,   0,   0,  13,
      68,   0,   0,  76,  47,   0,   0,   0,  85,   6,   0,  89,  25,
       4,  73,  88,  86,   0,   0,   0,
  };
  static const unsigned char aLen[98] = {
       5,   5,   4,   4,   9,   2,   5,   5,   6,   4,   3,   8,   2,
       4,   5,   3,   3,   7,  11,   2,   7,   4,   4,   6,   7,  10,
       9,   6,   6,   4,   6,   3,   7,   6,   7,   9,   7,   5,   5,
       9,   3,   7,   3,   7,   4,   5,   2,   7,   3,  10,   4,   7,
       6,   8,  10,   2,   9,   6,   5,   8,   6,   4,   6,   8,   2,
       4,   6,   5,   4,   4,   4,   5,   6,   9,   5,   8,   6,   7,
       4,   2,   6,   3,   6,   4,   5,   5,   5,   8,   7,   3,   4,
       5,   6,   5,   6,   6,   4,   5,
  };
  static const unsigned short int aOffset[98] = {
       0,   4,   7,  10,  10,  14,  19,  23,  26,  31,  33,  35,  40,
      42,  44,  48,  51,  53,  59,  68,  69,  75,  78,  81,  86,  92,
     101, 110, 115, 120, 123, 125, 125, 129, 133, 139, 147, 152, 157,
     160, 165, 169, 175, 175, 178, 181, 186, 188, 189, 193, 203, 207,
     214, 220, 228, 235, 235, 244, 250, 255, 262, 268, 272, 278, 279,
     286, 289, 293, 298, 302, 306, 310, 313, 319, 328, 332, 340, 346,
     353, 356, 356, 359, 362, 368, 372, 376, 381, 385, 393, 400, 402,
     406, 411, 417, 422, 428, 434, 437,
  };
  static const unsigned char aCode[98] = {
    TK_ABORT,      TK_TABLE,      TK_JOIN_KW,    TK_TEMP,       TK_TEMP,       
    TK_OR,         TK_AFTER,      TK_RAISE,      TK_SELECT,     TK_THEN,       
    TK_END,        TK_DATABASE,   TK_AS,         TK_EACH,       TK_CHECK,      
    TK_KEY,        TK_AND,        TK_DEFAULT,    TK_TRANSACTION,TK_ON,         
    TK_JOIN_KW,    TK_LIKE,       TK_ELSE,       TK_EXCEPT,     TK_TRIGGER,    
    TK_REFERENCES, TK_STATEMENT,  TK_ATTACH,     TK_HAVING,     TK_GLOB,       
    TK_BEFORE,     TK_FOR,        TK_FOREIGN,    TK_IGNORE,     TK_REPLACE,    
    TK_EXCLUSIVE,  TK_EXPLAIN,    TK_INDEX,      TK_BEGIN,      TK_INITIALLY,  
    TK_ALL,        TK_BETWEEN,    TK_NOT,        TK_NOTNULL,    TK_NULL,       
    TK_LIMIT,      TK_BY,         TK_CASCADE,    TK_ASC,        TK_DEFERRABLE, 
    TK_CASE,       TK_COLLATE,    TK_COMMIT,     TK_CONFLICT,   TK_CONSTRAINT, 
    TK_IN,         TK_INTERSECT,  TK_CREATE,     TK_JOIN_KW,    TK_DEFERRED,   
    TK_DELETE,     TK_DESC,       TK_DETACH,     TK_DISTINCT,   TK_IS,         
    TK_DROP,       TK_PRAGMA,     TK_MATCH,      TK_FAIL,       TK_FROM,       
    TK_JOIN_KW,    TK_GROUP,      TK_UPDATE,     TK_IMMEDIATE,  TK_JOIN_KW,    
    TK_RESTRICT,   TK_INSERT,     TK_INSTEAD,    TK_INTO,       TK_OF,         
    TK_OFFSET,     TK_SET,        TK_ISNULL,     TK_JOIN,       TK_ORDER,      
    TK_JOIN_KW,    TK_JOIN_KW,    TK_ROLLBACK,   TK_PRIMARY,    TK_ROW,        
    TK_WHEN,       TK_UNION,      TK_UNIQUE,     TK_USING,      TK_VACUUM,     
    TK_VALUES,     TK_VIEW,       TK_WHERE,      
  };
  int h, i;
  if( n<2 ) return TK_ID;
  h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 + 
      sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +
      n) % 154;
  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
      return aCode[i];
    }
  }
  return TK_ID;
}



/*
** If X is a character that can be used in an identifier and
** X&0x80==0 then isIdChar[X] will be 1.  If X&0x80==0x80 then
** X is always an identifier character.  (Hence all UTF-8
** characters can be part of an identifier).  isIdChar[X] will







|







|
|




|
|
|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35























































































36
37
38
39
40
41
42
43
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.94 2004/11/03 03:59:58 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>

/*
** The sqlite3KeywordCode 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.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.c, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.c and then included into this source file by
** the #include below.

*/























































































#include "keywordhash.c"


/*
** If X is a character that can be used in an identifier and
** X&0x80==0 then isIdChar[X] will be 1.  If X&0x80==0x80 then
** X is always an identifier character.  (Hence all UTF-8
** characters can be part of an identifier).  isIdChar[X] will

Changes to tool/mkkeywordhash.c.

11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28


































































29
30
31
32
33
34

35
36
37
38

39
40
41
42
43
44
45
46
47
48
49
50
51



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
196
197
198
199
200
201
202










203
204
205
206
207
208
209
** All the keywords of the SQL language are stored as 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 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 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 */
};

/*


































































** These are the keywords
*/
static Keyword aKeywordTable[] = {
  { "ABORT",            "TK_ABORT",        },
  { "AFTER",            "TK_AFTER",        },
  { "ALL",              "TK_ALL",          },

  { "AND",              "TK_AND",          },
  { "AS",               "TK_AS",           },
  { "ASC",              "TK_ASC",          },
  { "ATTACH",           "TK_ATTACH",       },

  { "BEFORE",           "TK_BEFORE",       },
  { "BEGIN",            "TK_BEGIN",        },
  { "BETWEEN",          "TK_BETWEEN",      },
  { "BY",               "TK_BY",           },
  { "CASCADE",          "TK_CASCADE",      },
  { "CASE",             "TK_CASE",         },
  { "CHECK",            "TK_CHECK",        },
  { "COLLATE",          "TK_COLLATE",      },
  { "COMMIT",           "TK_COMMIT",       },
  { "CONFLICT",         "TK_CONFLICT",     },
  { "CONSTRAINT",       "TK_CONSTRAINT",   },
  { "CREATE",           "TK_CREATE",       },
  { "CROSS",            "TK_JOIN_KW",      },



  { "DATABASE",         "TK_DATABASE",     },
  { "DEFAULT",          "TK_DEFAULT",      },
  { "DEFERRED",         "TK_DEFERRED",     },
  { "DEFERRABLE",       "TK_DEFERRABLE",   },
  { "DELETE",           "TK_DELETE",       },
  { "DESC",             "TK_DESC",         },
  { "DETACH",           "TK_DETACH",       },
  { "DISTINCT",         "TK_DISTINCT",     },
  { "DROP",             "TK_DROP",         },
  { "END",              "TK_END",          },
  { "EACH",             "TK_EACH",         },
  { "ELSE",             "TK_ELSE",         },
  { "EXCEPT",           "TK_EXCEPT",       },
  { "EXCLUSIVE",        "TK_EXCLUSIVE",    },
  { "EXPLAIN",          "TK_EXPLAIN",      },
  { "FAIL",             "TK_FAIL",         },
  { "FOR",              "TK_FOR",          },
  { "FOREIGN",          "TK_FOREIGN",      },
  { "FROM",             "TK_FROM",         },
  { "FULL",             "TK_JOIN_KW",      },
  { "GLOB",             "TK_GLOB",         },
  { "GROUP",            "TK_GROUP",        },
  { "HAVING",           "TK_HAVING",       },
  { "IGNORE",           "TK_IGNORE",       },
  { "IMMEDIATE",        "TK_IMMEDIATE",    },
  { "IN",               "TK_IN",           },
  { "INDEX",            "TK_INDEX",        },
  { "INITIALLY",        "TK_INITIALLY",    },
  { "INNER",            "TK_JOIN_KW",      },
  { "INSERT",           "TK_INSERT",       },
  { "INSTEAD",          "TK_INSTEAD",      },
  { "INTERSECT",        "TK_INTERSECT",    },
  { "INTO",             "TK_INTO",         },
  { "IS",               "TK_IS",           },
  { "ISNULL",           "TK_ISNULL",       },
  { "JOIN",             "TK_JOIN",         },
  { "KEY",              "TK_KEY",          },
  { "LEFT",             "TK_JOIN_KW",      },
  { "LIKE",             "TK_LIKE",         },
  { "LIMIT",            "TK_LIMIT",        },
  { "MATCH",            "TK_MATCH",        },
  { "NATURAL",          "TK_JOIN_KW",      },
  { "NOT",              "TK_NOT",          },
  { "NOTNULL",          "TK_NOTNULL",      },
  { "NULL",             "TK_NULL",         },
  { "OF",               "TK_OF",           },
  { "OFFSET",           "TK_OFFSET",       },
  { "ON",               "TK_ON",           },
  { "OR",               "TK_OR",           },
  { "ORDER",            "TK_ORDER",        },
  { "OUTER",            "TK_JOIN_KW",      },
  { "PRAGMA",           "TK_PRAGMA",       },
  { "PRIMARY",          "TK_PRIMARY",      },
  { "RAISE",            "TK_RAISE",        },
  { "REFERENCES",       "TK_REFERENCES",   },


  { "REPLACE",          "TK_REPLACE",      },
  { "RESTRICT",         "TK_RESTRICT",     },
  { "RIGHT",            "TK_JOIN_KW",      },
  { "ROLLBACK",         "TK_ROLLBACK",     },
  { "ROW",              "TK_ROW",          },
  { "SELECT",           "TK_SELECT",       },
  { "SET",              "TK_SET",          },
  { "STATEMENT",        "TK_STATEMENT",    },
  { "TABLE",            "TK_TABLE",        },
  { "TEMP",             "TK_TEMP",         },
  { "TEMPORARY",        "TK_TEMP",         },
  { "THEN",             "TK_THEN",         },
  { "TRANSACTION",      "TK_TRANSACTION",  },
  { "TRIGGER",          "TK_TRIGGER",      },
  { "UNION",            "TK_UNION",        },
  { "UNIQUE",           "TK_UNIQUE",       },
  { "UPDATE",           "TK_UPDATE",       },
  { "USING",            "TK_USING",        },
  { "VACUUM",           "TK_VACUUM",       },
  { "VALUES",           "TK_VALUES",       },
  { "VIEW",             "TK_VIEW",         },
  { "WHEN",             "TK_WHEN",         },
  { "WHERE",            "TK_WHERE",        },
};

/* Number of keywords */
#define NKEYWORD (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]))

/* An array to map all upper-case characters into their corresponding
** lower-case character. 
*/
const unsigned char sqlite3UpperToLower[] = {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
................................................................................
*/
int main(int argc, char **argv){
  int i, j, k, h;
  int bestSize, bestCount;
  int count;
  int nChar;
  int aHash[1000];  /* 1000 is much bigger than NKEYWORD */











  /* Fill in the lengths of strings and hashes for all entries. */
  for(i=0; i<NKEYWORD; i++){
    Keyword *p = &aKeywordTable[i];
    p->len = strlen(p->zName);
    p->hash = UpperToLower[p->zName[0]]*5 +
              UpperToLower[p->zName[p->len-1]]*3 + p->len;







>











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
|
|
>
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



|







 







>
>
>
>
>
>
>
>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
** All the keywords of the SQL language are stored as 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 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 */
};

/*
** Define masks used to determine which keywords are allowed
*/
#ifdef SQLITE_OMIT_ALTER_TABLE
#  define ALTER      0
#else
#  define ALTER      1
#endif
#define ALWAYS     2
#ifdef SQLITE_OMIT_ATTACH
#  define ATTACH     0
#else
#  define ATTACH     4
#endif
#ifdef SQLITE_OMIT_AUTOINCREMENT
#  define AUTOINCR   0
#else
#  define AUTOINCR   8
#endif
#ifdef SQLITE_OMIT_COMPOUND_SELECT
#  define COMPOUND   0
#else
#  define COMPOUND   16
#endif
#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
#  define CONFLICT   0
#else
#  define CONFLICT   32
#endif
#ifdef SQLITE_OMIT_EXPLAIN
#  define EXPLAIN    0
#else
#  define EXPLAIN    64
#endif
#ifdef SQLITE_OMIT_FOREIGN_KEY
#  define FKEY       0
#else
#  define FKEY       128
#endif
#ifdef SQLITE_OMIT_PRAGMA
#  define PRAGMA     0
#else
#  define PRAGMA     256
#endif
#ifdef SQLITE_OMIT_REINDEX
#  define REINDEX    0
#else
#  define REINDEX    512
#endif
#ifdef SQLITE_OMIT_TRIGGER
#  define TRIGGER    0
#else
#  define TRIGGER    1024
#endif
#ifdef SQLITE_OMIT_VACUUM
#  define VACUUM     0
#else
#  define VACUUM     2048
#endif
#ifdef SQLITE_OMIT_VIEW
#  define VIEW       0
#else
#  define VIEW       4096
#endif


/*
** These are the keywords
*/
static Keyword aKeywordTable[] = {
  { "ABORT",            "TK_ABORT",        CONFLICT|TRIGGER       },
  { "AFTER",            "TK_AFTER",        TRIGGER                },
  { "ALL",              "TK_ALL",          ALWAYS                 },
  { "ALTER",            "TK_ALTER",        ALTER                  },
  { "AND",              "TK_AND",          ALWAYS                 },
  { "AS",               "TK_AS",           ALWAYS                 },
  { "ASC",              "TK_ASC",          ALWAYS                 },
  { "ATTACH",           "TK_ATTACH",       ATTACH                 },
  { "AUTOINCREMENT",    "TK_AUTOINCR",     AUTOINCR               },
  { "BEFORE",           "TK_BEFORE",       TRIGGER                },
  { "BEGIN",            "TK_BEGIN",        ALWAYS                 },
  { "BETWEEN",          "TK_BETWEEN",      ALWAYS                 },
  { "BY",               "TK_BY",           ALWAYS                 },
  { "CASCADE",          "TK_CASCADE",      FKEY                   },
  { "CASE",             "TK_CASE",         ALWAYS                 },
  { "CHECK",            "TK_CHECK",        ALWAYS                 },
  { "COLLATE",          "TK_COLLATE",      ALWAYS                 },
  { "COMMIT",           "TK_COMMIT",       ALWAYS                 },
  { "CONFLICT",         "TK_CONFLICT",     CONFLICT               },
  { "CONSTRAINT",       "TK_CONSTRAINT",   ALWAYS                 },
  { "CREATE",           "TK_CREATE",       ALWAYS                 },
  { "CROSS",            "TK_JOIN_KW",      ALWAYS                 },
  { "CURRENT_DATE",     "TK_CDATE",        ALWAYS                 },
  { "CURRENT_TIME",     "TK_CTIME",        ALWAYS                 },
  { "CURRENT_TIMESTAMP","TK_CTIMESTAMP",   ALWAYS                 },
  { "DATABASE",         "TK_DATABASE",     ATTACH                 },
  { "DEFAULT",          "TK_DEFAULT",      ALWAYS                 },
  { "DEFERRED",         "TK_DEFERRED",     FKEY                   },
  { "DEFERRABLE",       "TK_DEFERRABLE",   FKEY                   },
  { "DELETE",           "TK_DELETE",       ALWAYS                 },
  { "DESC",             "TK_DESC",         ALWAYS                 },
  { "DETACH",           "TK_DETACH",       ATTACH                 },
  { "DISTINCT",         "TK_DISTINCT",     ALWAYS                 },
  { "DROP",             "TK_DROP",         ALWAYS                 },
  { "END",              "TK_END",          ALWAYS                 },
  { "EACH",             "TK_EACH",         TRIGGER                },
  { "ELSE",             "TK_ELSE",         ALWAYS                 },
  { "EXCEPT",           "TK_EXCEPT",       COMPOUND               },
  { "EXCLUSIVE",        "TK_EXCLUSIVE",    ALWAYS                 },
  { "EXPLAIN",          "TK_EXPLAIN",      EXPLAIN                },
  { "FAIL",             "TK_FAIL",         CONFLICT|TRIGGER       },
  { "FOR",              "TK_FOR",          TRIGGER                },
  { "FOREIGN",          "TK_FOREIGN",      FKEY                   },
  { "FROM",             "TK_FROM",         ALWAYS                 },
  { "FULL",             "TK_JOIN_KW",      ALWAYS                 },
  { "GLOB",             "TK_GLOB",         ALWAYS                 },
  { "GROUP",            "TK_GROUP",        ALWAYS                 },
  { "HAVING",           "TK_HAVING",       ALWAYS                 },
  { "IGNORE",           "TK_IGNORE",       CONFLICT|TRIGGER       },
  { "IMMEDIATE",        "TK_IMMEDIATE",    FKEY                   },
  { "IN",               "TK_IN",           ALWAYS                 },
  { "INDEX",            "TK_INDEX",        ALWAYS                 },
  { "INITIALLY",        "TK_INITIALLY",    FKEY                   },
  { "INNER",            "TK_JOIN_KW",      ALWAYS                 },
  { "INSERT",           "TK_INSERT",       ALWAYS                 },
  { "INSTEAD",          "TK_INSTEAD",      TRIGGER                },
  { "INTERSECT",        "TK_INTERSECT",    COMPOUND               },
  { "INTO",             "TK_INTO",         ALWAYS                 },
  { "IS",               "TK_IS",           ALWAYS                 },
  { "ISNULL",           "TK_ISNULL",       ALWAYS                 },
  { "JOIN",             "TK_JOIN",         ALWAYS                 },
  { "KEY",              "TK_KEY",          ALWAYS                 },
  { "LEFT",             "TK_JOIN_KW",      ALWAYS                 },
  { "LIKE",             "TK_LIKE",         ALWAYS                 },
  { "LIMIT",            "TK_LIMIT",        ALWAYS                 },
  { "MATCH",            "TK_MATCH",        ALWAYS                 },
  { "NATURAL",          "TK_JOIN_KW",      ALWAYS                 },
  { "NOT",              "TK_NOT",          ALWAYS                 },
  { "NOTNULL",          "TK_NOTNULL",      ALWAYS                 },
  { "NULL",             "TK_NULL",         ALWAYS                 },
  { "OF",               "TK_OF",           ALWAYS                 },
  { "OFFSET",           "TK_OFFSET",       ALWAYS                 },
  { "ON",               "TK_ON",           ALWAYS                 },
  { "OR",               "TK_OR",           ALWAYS                 },
  { "ORDER",            "TK_ORDER",        ALWAYS                 },
  { "OUTER",            "TK_JOIN_KW",      ALWAYS                 },
  { "PRAGMA",           "TK_PRAGMA",       PRAGMA                 },
  { "PRIMARY",          "TK_PRIMARY",      ALWAYS                 },
  { "RAISE",            "TK_RAISE",        TRIGGER                },
  { "REFERENCES",       "TK_REFERENCES",   FKEY                   },
  { "REINDEX",          "TK_REINDEX",      REINDEX                },
  { "RENAME",           "TK_RENAME",       ALTER                  },
  { "REPLACE",          "TK_REPLACE",      CONFLICT               },
  { "RESTRICT",         "TK_RESTRICT",     FKEY                   },
  { "RIGHT",            "TK_JOIN_KW",      ALWAYS                 },
  { "ROLLBACK",         "TK_ROLLBACK",     ALWAYS                 },
  { "ROW",              "TK_ROW",          TRIGGER                },
  { "SELECT",           "TK_SELECT",       ALWAYS                 },
  { "SET",              "TK_SET",          ALWAYS                 },
  { "STATEMENT",        "TK_STATEMENT",    TRIGGER                },
  { "TABLE",            "TK_TABLE",        ALWAYS                 },
  { "TEMP",             "TK_TEMP",         ALWAYS                 },
  { "TEMPORARY",        "TK_TEMP",         ALWAYS                 },
  { "THEN",             "TK_THEN",         ALWAYS                 },
  { "TRANSACTION",      "TK_TRANSACTION",  ALWAYS                 },
  { "TRIGGER",          "TK_TRIGGER",      TRIGGER                },
  { "UNION",            "TK_UNION",        COMPOUND               },
  { "UNIQUE",           "TK_UNIQUE",       ALWAYS                 },
  { "UPDATE",           "TK_UPDATE",       ALWAYS                 },
  { "USING",            "TK_USING",        ALWAYS                 },
  { "VACUUM",           "TK_VACUUM",       VACUUM                 },
  { "VALUES",           "TK_VALUES",       ALWAYS                 },
  { "VIEW",             "TK_VIEW",         VIEW                   },
  { "WHEN",             "TK_WHEN",         ALWAYS                 },
  { "WHERE",            "TK_WHERE",        ALWAYS                 },
};

/* Number of keywords */
static int NKEYWORD = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));

/* An array to map all upper-case characters into their corresponding
** lower-case character. 
*/
const unsigned char sqlite3UpperToLower[] = {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
................................................................................
*/
int main(int argc, char **argv){
  int i, j, k, h;
  int bestSize, bestCount;
  int count;
  int nChar;
  int aHash[1000];  /* 1000 is much bigger than NKEYWORD */

  /* 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 = strlen(p->zName);
    p->hash = UpperToLower[p->zName[0]]*5 +
              UpperToLower[p->zName[p->len-1]]*3 + p->len;