summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/tool
diff options
context:
space:
mode:
authorScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
committerScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
commit31dade5280849135b00fd1c5e53d057732a72776 (patch)
tree564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/tool
parent7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff)
downloadphp-git-31dade5280849135b00fd1c5e53d057732a72776.tar.gz
MFB: Update bundled SQLite to 3.5.6
Diffstat (limited to 'ext/pdo_sqlite/sqlite/tool')
-rw-r--r--ext/pdo_sqlite/sqlite/tool/fragck.tcl149
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lemon.c295
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lempar.c147
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c120
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl278
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl145
-rw-r--r--ext/pdo_sqlite/sqlite/tool/omittest.tcl176
-rw-r--r--ext/pdo_sqlite/sqlite/tool/soak1.tcl103
-rw-r--r--ext/pdo_sqlite/sqlite/tool/spaceanal.tcl65
9 files changed, 1264 insertions, 214 deletions
diff --git a/ext/pdo_sqlite/sqlite/tool/fragck.tcl b/ext/pdo_sqlite/sqlite/tool/fragck.tcl
new file mode 100644
index 0000000000..35e76f482b
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/fragck.tcl
@@ -0,0 +1,149 @@
+# Run this TCL script using "testfixture" to get a report that shows
+# the sequence of database pages used by a particular table or index.
+# This information is used for fragmentation analysis.
+#
+
+# Get the name of the database to analyze
+#
+
+if {[llength $argv]!=2} {
+ puts stderr "Usage: $argv0 database-name table-or-index-name"
+ exit 1
+}
+set file_to_analyze [lindex $argv 0]
+if {![file exists $file_to_analyze]} {
+ puts stderr "No such file: $file_to_analyze"
+ exit 1
+}
+if {![file readable $file_to_analyze]} {
+ puts stderr "File is not readable: $file_to_analyze"
+ exit 1
+}
+if {[file size $file_to_analyze]<512} {
+ puts stderr "Empty or malformed database: $file_to_analyze"
+ exit 1
+}
+set objname [lindex $argv 1]
+
+# Open the database
+#
+sqlite3 db [lindex $argv 0]
+set DB [btree_open [lindex $argv 0] 1000 0]
+
+# This proc is a wrapper around the btree_cursor_info command. The
+# second argument is an open btree cursor returned by [btree_cursor].
+# The first argument is the name of an array variable that exists in
+# the scope of the caller. If the third argument is non-zero, then
+# info is returned for the page that lies $up entries upwards in the
+# tree-structure. (i.e. $up==1 returns the parent page, $up==2 the
+# grandparent etc.)
+#
+# The following entries in that array are filled in with information retrieved
+# using [btree_cursor_info]:
+#
+# $arrayvar(page_no) = The page number
+# $arrayvar(entry_no) = The entry number
+# $arrayvar(page_entries) = Total number of entries on this page
+# $arrayvar(cell_size) = Cell size (local payload + header)
+# $arrayvar(page_freebytes) = Number of free bytes on this page
+# $arrayvar(page_freeblocks) = Number of free blocks on the page
+# $arrayvar(payload_bytes) = Total payload size (local + overflow)
+# $arrayvar(header_bytes) = Header size in bytes
+# $arrayvar(local_payload_bytes) = Local payload size
+# $arrayvar(parent) = Parent page number
+#
+proc cursor_info {arrayvar csr {up 0}} {
+ upvar $arrayvar a
+ foreach [list a(page_no) \
+ a(entry_no) \
+ a(page_entries) \
+ a(cell_size) \
+ a(page_freebytes) \
+ a(page_freeblocks) \
+ a(payload_bytes) \
+ a(header_bytes) \
+ a(local_payload_bytes) \
+ a(parent) \
+ a(first_ovfl) ] [btree_cursor_info $csr $up] break
+}
+
+# Determine the page-size of the database. This global variable is used
+# throughout the script.
+#
+set pageSize [db eval {PRAGMA page_size}]
+
+# Find the root page of table or index to be analyzed. Also find out
+# if the object is a table or an index.
+#
+if {$objname=="sqlite_master"} {
+ set rootpage 1
+ set type table
+} else {
+ db eval {
+ SELECT rootpage, type FROM sqlite_master
+ WHERE name=$objname
+ } break
+ if {![info exists rootpage]} {
+ puts stderr "no such table or index: $objname"
+ exit 1
+ }
+ if {$type!="table" && $type!="index"} {
+ puts stderr "$objname is something other than a table or index"
+ exit 1
+ }
+ if {![string is integer -strict $rootpage]} {
+ puts stderr "invalid root page for $objname: $rootpage"
+ exit 1
+ }
+}
+
+# The cursor $csr is pointing to an entry. Print out information
+# about the page that $up levels above that page that contains
+# the entry. If $up==0 use the page that contains the entry.
+#
+# If information about the page has been printed already, then
+# this is a no-op.
+#
+proc page_info {csr up} {
+ global seen
+ cursor_info ci $csr $up
+ set pg $ci(page_no)
+ if {[info exists seen($pg)]} return
+ set seen($pg) 1
+
+ # Do parent pages first
+ #
+ if {$ci(parent)} {
+ page_info $csr [expr {$up+1}]
+ }
+
+ # Find the depth of this page
+ #
+ set depth 1
+ set i $up
+ while {$ci(parent)} {
+ incr i
+ incr depth
+ cursor_info ci $csr $i
+ }
+
+ # print the results
+ #
+ puts [format {LEVEL %d: %6d} $depth $pg]
+}
+
+
+
+
+# Loop through the object and print out page numbers
+#
+set csr [btree_cursor $DB $rootpage 0]
+for {btree_first $csr} {![btree_eof $csr]} {btree_next $csr} {
+ page_info $csr 0
+ set i 1
+ foreach pg [btree_ovfl_info $DB $csr] {
+ puts [format {OVFL %3d: %6d} $i $pg]
+ incr i
+ }
+}
+exit 0
diff --git a/ext/pdo_sqlite/sqlite/tool/lemon.c b/ext/pdo_sqlite/sqlite/tool/lemon.c
index 759e1c3786..e613f77581 100644
--- a/ext/pdo_sqlite/sqlite/tool/lemon.c
+++ b/ext/pdo_sqlite/sqlite/tool/lemon.c
@@ -11,6 +11,7 @@
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
+#include <assert.h>
#ifndef __WIN32__
# if defined(_WIN32) || defined(WIN32)
@@ -18,6 +19,12 @@
# endif
#endif
+#ifdef __WIN32__
+extern int access();
+#else
+#include <unistd.h>
+#endif
+
/* #define PRIVATE static */
#define PRIVATE
@@ -27,20 +34,10 @@
#define MAXRHS 1000
#endif
-char *msort();
-extern void *malloc();
+static char *msort(char*,char**,int(*)(const char*,const char*));
-/******** From the file "action.h" *************************************/
-struct action *Action_new();
-struct action *Action_sort();
-
-/********* From the file "assert.h" ************************************/
-void myassert();
-#ifndef NDEBUG
-# define assert(X) if(!(X))myassert(__FILE__,__LINE__)
-#else
-# define assert(X)
-#endif
+static struct action *Action_new(void);
+static struct action *Action_sort(struct action *);
/********** From the file "build.h" ************************************/
void FindRulePrecedences();
@@ -111,7 +108,7 @@ int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */
** Principal data structures for the LEMON parser generator.
*/
-typedef enum {B_FALSE=0, B_TRUE} Boolean;
+typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean;
/* Symbols (terminals and nonterminals) of the grammar are stored
** in the following: */
@@ -134,6 +131,7 @@ struct symbol {
} assoc; /* Associativity if predecence is defined */
char *firstset; /* First-set for all rules of this symbol */
Boolean lambda; /* True if NT and can generate an empty string */
+ int useCnt; /* Number of times used */
char *destructor; /* Code which executes whenever this symbol is
** popped from the stack during error processing */
int destructorln; /* Line number of destructor code */
@@ -152,6 +150,7 @@ struct symbol {
struct rule {
struct symbol *lhs; /* Left-hand side of the rule */
char *lhsalias; /* Alias for the LHS (NULL if none) */
+ int lhsStart; /* True if left-hand side is the start symbol */
int ruleline; /* Line number for the rule */
int nrhs; /* Number of RHS symbols */
struct symbol **rhs; /* The RHS symbols */
@@ -193,7 +192,9 @@ struct action {
ACCEPT,
REDUCE,
ERROR,
- CONFLICT, /* Was a reduce, but part of a conflict */
+ SSCONFLICT, /* A shift/shift conflict */
+ SRCONFLICT, /* Was a reduce, but part of a conflict */
+ RRCONFLICT, /* Was a reduce, but part of a conflict */
SH_RESOLVED, /* Was a shift. Precedence resolved conflict */
RD_RESOLVED, /* Was reduce. Precedence resolved conflict */
NOT_USED /* Deleted by compression */
@@ -332,14 +333,14 @@ void Configtable_clear(/* int(*)(struct config *) */);
*/
/* Allocate a new parser action */
-struct action *Action_new(){
+static struct action *Action_new(void){
static struct action *freelist = 0;
struct action *new;
if( freelist==0 ){
int i;
int amt = 100;
- freelist = (struct action *)malloc( sizeof(struct action)*amt );
+ freelist = (struct action *)calloc(amt, sizeof(struct action));
if( freelist==0 ){
fprintf(stderr,"Unable to allocate memory for a new parser action.");
exit(1);
@@ -352,27 +353,31 @@ struct action *Action_new(){
return new;
}
-/* Compare two actions */
-static int actioncmp(ap1,ap2)
-struct action *ap1;
-struct action *ap2;
-{
+/* Compare two actions for sorting purposes. Return negative, zero, or
+** positive if the first action is less than, equal to, or greater than
+** the first
+*/
+static int actioncmp(
+ struct action *ap1,
+ struct action *ap2
+){
int rc;
rc = ap1->sp->index - ap2->sp->index;
- if( rc==0 ) rc = (int)ap1->type - (int)ap2->type;
if( rc==0 ){
- assert( ap1->type==REDUCE || ap1->type==RD_RESOLVED || ap1->type==CONFLICT);
- assert( ap2->type==REDUCE || ap2->type==RD_RESOLVED || ap2->type==CONFLICT);
+ rc = (int)ap1->type - (int)ap2->type;
+ }
+ if( rc==0 && ap1->type==REDUCE ){
rc = ap1->x.rp->index - ap2->x.rp->index;
}
return rc;
}
/* Sort parser actions */
-struct action *Action_sort(ap)
-struct action *ap;
-{
- ap = (struct action *)msort((char *)ap,(char **)&ap->next,actioncmp);
+static struct action *Action_sort(
+ struct action *ap
+){
+ ap = (struct action *)msort((char *)ap,(char **)&ap->next,
+ (int(*)(const char*,const char*))actioncmp);
return ap;
}
@@ -437,7 +442,7 @@ void acttab_free(acttab *p){
/* Allocate a new acttab structure */
acttab *acttab_alloc(void){
- acttab *p = malloc( sizeof(*p) );
+ acttab *p = calloc( 1, sizeof(*p) );
if( p==0 ){
fprintf(stderr,"Unable to allocate memory for a new acttab.");
exit(1);
@@ -558,17 +563,6 @@ int acttab_insert(acttab *p){
return i - p->mnLookahead;
}
-/********************** From the file "assert.c" ****************************/
-/*
-** A more efficient way of handling assertions.
-*/
-void myassert(file,line)
-char *file;
-int line;
-{
- fprintf(stderr,"Assertion failed on line %d of file \"%s\"\n",line,file);
- exit(1);
-}
/********************** From the file "build.c" *****************************/
/*
** Routines to construction the finite state machine for the LEMON
@@ -622,7 +616,7 @@ struct lemon *lemp;
int progress;
for(i=0; i<lemp->nsymbol; i++){
- lemp->symbols[i]->lambda = B_FALSE;
+ lemp->symbols[i]->lambda = LEMON_FALSE;
}
for(i=lemp->nterminal; i<lemp->nsymbol; i++){
lemp->symbols[i]->firstset = SetNew();
@@ -635,10 +629,10 @@ struct lemon *lemp;
if( rp->lhs->lambda ) continue;
for(i=0; i<rp->nrhs; i++){
struct symbol *sp = rp->rhs[i];
- if( sp->type!=TERMINAL || sp->lambda==B_FALSE ) break;
+ if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break;
}
if( i==rp->nrhs ){
- rp->lhs->lambda = B_TRUE;
+ rp->lhs->lambda = LEMON_TRUE;
progress = 1;
}
}
@@ -661,10 +655,10 @@ struct lemon *lemp;
}
break;
}else if( s1==s2 ){
- if( s1->lambda==B_FALSE ) break;
+ if( s1->lambda==LEMON_FALSE ) break;
}else{
progress += SetUnion(s1->firstset,s2->firstset);
- if( s2->lambda==B_FALSE ) break;
+ if( s2->lambda==LEMON_FALSE ) break;
}
}
}
@@ -721,6 +715,7 @@ does not work properly.",sp->name);
** left-hand side */
for(rp=sp->rule; rp; rp=rp->nextlhs){
struct config *newcfp;
+ rp->lhsStart = 1;
newcfp = Configlist_addbasis(rp,0);
SetAdd(newcfp->fws,0);
}
@@ -972,7 +967,7 @@ struct lemon *lemp;
struct action *ap, *nap;
struct state *stp;
stp = lemp->sorted[i];
- assert( stp->ap );
+ /* assert( stp->ap ); */
stp->ap = Action_sort(stp->ap);
for(ap=stp->ap; ap && ap->next; ap=ap->next){
for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
@@ -984,11 +979,11 @@ struct lemon *lemp;
}
/* Report an error for each rule that can never be reduced. */
- for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = B_FALSE;
+ for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE;
for(i=0; i<lemp->nstate; i++){
struct action *ap;
for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
- if( ap->type==REDUCE ) ap->x.rp->canReduce = B_TRUE;
+ if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE;
}
}
for(rp=lemp->rule; rp; rp=rp->next){
@@ -1019,12 +1014,16 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
struct symbol *spx, *spy;
int errcnt = 0;
assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */
+ if( apx->type==SHIFT && apy->type==SHIFT ){
+ apy->type = SSCONFLICT;
+ errcnt++;
+ }
if( apx->type==SHIFT && apy->type==REDUCE ){
spx = apx->sp;
spy = apy->x.rp->precsym;
if( spy==0 || spx->prec<0 || spy->prec<0 ){
/* Not enough precedence information. */
- apy->type = CONFLICT;
+ apy->type = SRCONFLICT;
errcnt++;
}else if( spx->prec>spy->prec ){ /* Lower precedence wins */
apy->type = RD_RESOLVED;
@@ -1036,7 +1035,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
apx->type = SH_RESOLVED;
}else{
assert( spx->prec==spy->prec && spx->assoc==NONE );
- apy->type = CONFLICT;
+ apy->type = SRCONFLICT;
errcnt++;
}
}else if( apx->type==REDUCE && apy->type==REDUCE ){
@@ -1044,7 +1043,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
spy = apy->x.rp->precsym;
if( spx==0 || spy==0 || spx->prec<0 ||
spy->prec<0 || spx->prec==spy->prec ){
- apy->type = CONFLICT;
+ apy->type = RRCONFLICT;
errcnt++;
}else if( spx->prec>spy->prec ){
apy->type = RD_RESOLVED;
@@ -1055,10 +1054,14 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
assert(
apx->type==SH_RESOLVED ||
apx->type==RD_RESOLVED ||
- apx->type==CONFLICT ||
+ apx->type==SSCONFLICT ||
+ apx->type==SRCONFLICT ||
+ apx->type==RRCONFLICT ||
apy->type==SH_RESOLVED ||
apy->type==RD_RESOLVED ||
- apy->type==CONFLICT
+ apy->type==SSCONFLICT ||
+ apy->type==SRCONFLICT ||
+ apy->type==RRCONFLICT
);
/* The REDUCE/SHIFT case cannot happen because SHIFTs come before
** REDUCEs on the list. If we reach this point it must be because
@@ -1084,7 +1087,7 @@ PRIVATE struct config *newconfig(){
if( freelist==0 ){
int i;
int amt = 3;
- freelist = (struct config *)malloc( sizeof(struct config)*amt );
+ freelist = (struct config *)calloc( amt, sizeof(struct config) );
if( freelist==0 ){
fprintf(stderr,"Unable to allocate memory for a new configuration.");
exit(1);
@@ -1218,7 +1221,7 @@ struct lemon *lemp;
break;
}else{
SetUnion(newcfp->fws,xsp->firstset);
- if( xsp->lambda==B_FALSE ) break;
+ if( xsp->lambda==LEMON_FALSE ) break;
}
}
if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
@@ -1435,6 +1438,7 @@ char **argv;
lem.basisflag = basisflag;
Symbol_new("$");
lem.errsym = Symbol_new("error");
+ lem.errsym->useCnt = 0;
/* Parse the input file */
Parse(&lem);
@@ -1460,7 +1464,7 @@ char **argv;
Reprint(&lem);
}else{
/* Initialize the size for all follow and first sets */
- SetSize(lem.nterminal);
+ SetSize(lem.nterminal+1);
/* Find the precedence for every production rule (that has one) */
FindRulePrecedences(&lem);
@@ -1558,12 +1562,12 @@ char **argv;
** The "next" pointers for elements in the lists a and b are
** changed.
*/
-static char *merge(a,b,cmp,offset)
-char *a;
-char *b;
-int (*cmp)();
-int offset;
-{
+static char *merge(
+ char *a,
+ char *b,
+ int (*cmp)(const char*,const char*),
+ int offset
+){
char *ptr, *head;
if( a==0 ){
@@ -1610,11 +1614,11 @@ int offset;
** The "next" pointers for elements in list are changed.
*/
#define LISTSIZE 30
-char *msort(list,next,cmp)
-char *list;
-char **next;
-int (*cmp)();
-{
+static char *msort(
+ char *list,
+ char **next,
+ int (*cmp)(const char*,const char*)
+){
unsigned long offset;
char *ep;
char *set[LISTSIZE];
@@ -2097,8 +2101,8 @@ to follow the previous rule.");
case IN_RHS:
if( x[0]=='.' ){
struct rule *rp;
- rp = (struct rule *)malloc( sizeof(struct rule) +
- sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
+ rp = (struct rule *)calloc( sizeof(struct rule) +
+ sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
if( rp==0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
"Can't allocate enough memory for this rule.");
@@ -2134,7 +2138,7 @@ to follow the previous rule.");
}else if( isalpha(x[0]) ){
if( psp->nrhs>=MAXRHS ){
ErrorMsg(psp->filename,psp->tokenlineno,
- "Too many symbols on RHS or rule beginning at \"%s\".",
+ "Too many symbols on RHS of rule beginning at \"%s\".",
x);
psp->errorcnt++;
psp->state = RESYNC_AFTER_RULE_ERROR;
@@ -2147,11 +2151,11 @@ to follow the previous rule.");
struct symbol *msp = psp->rhs[psp->nrhs-1];
if( msp->type!=MULTITERMINAL ){
struct symbol *origsp = msp;
- msp = malloc(sizeof(*msp));
+ msp = calloc(1,sizeof(*msp));
memset(msp, 0, sizeof(*msp));
msp->type = MULTITERMINAL;
msp->nsubsym = 1;
- msp->subsym = malloc(sizeof(struct symbol*));
+ msp->subsym = calloc(1,sizeof(struct symbol*));
msp->subsym[0] = origsp;
msp->name = origsp->name;
psp->rhs[psp->nrhs-1] = msp;
@@ -2396,9 +2400,9 @@ to follow the previous rule.");
static void preprocess_input(char *z){
int i, j, k, n;
int exclude = 0;
- int start;
+ int start = 0;
int lineno = 1;
- int start_lineno;
+ int start_lineno = 1;
for(i=0; z[i]; i++){
if( z[i]=='\n' ) lineno++;
if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
@@ -2456,6 +2460,7 @@ struct lemon *gp;
char *cp, *nextcp;
int startline = 0;
+ memset(&ps, '\0', sizeof(ps));
ps.gp = gp;
ps.filename = gp->filename;
ps.errorcnt = 0;
@@ -2603,7 +2608,7 @@ struct plink *Plink_new(){
if( plink_freelist==0 ){
int i;
int amt = 100;
- plink_freelist = (struct plink *)malloc( sizeof(struct plink)*amt );
+ plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
if( plink_freelist==0 ){
fprintf(stderr,
"Unable to allocate memory for a new follow-set propagation link.\n");
@@ -2829,10 +2834,15 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
case ERROR:
fprintf(fp,"%*s error",indent,ap->sp->name);
break;
- case CONFLICT:
+ case SRCONFLICT:
+ case RRCONFLICT:
fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
indent,ap->sp->name,ap->x.rp->index);
break;
+ case SSCONFLICT:
+ fprintf(fp,"%*s shift %d ** Parsing conflict **",
+ indent,ap->sp->name,ap->x.stp->statenum);
+ break;
case SH_RESOLVED:
case RD_RESOLVED:
case NOT_USED:
@@ -2854,7 +2864,6 @@ struct lemon *lemp;
fp = file_open(lemp,".out","wb");
if( fp==0 ) return;
- fprintf(fp," \b");
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
fprintf(fp,"State %d:\n",stp->statenum);
@@ -2884,6 +2893,27 @@ struct lemon *lemp;
}
fprintf(fp,"\n");
}
+ fprintf(fp, "----------------------------------------------------\n");
+ fprintf(fp, "Symbols:\n");
+ for(i=0; i<lemp->nsymbol; i++){
+ int j;
+ struct symbol *sp;
+
+ sp = lemp->symbols[i];
+ fprintf(fp, " %3d: %s", i, sp->name);
+ if( sp->type==NONTERMINAL ){
+ fprintf(fp, ":");
+ if( sp->lambda ){
+ fprintf(fp, " <lambda>");
+ }
+ for(j=0; j<lemp->nterminal; j++){
+ if( sp->firstset && SetFind(sp->firstset, j) ){
+ fprintf(fp, " %s", lemp->symbols[j]->name);
+ }
+ }
+ }
+ fprintf(fp, "\n");
+ }
fclose(fp);
return;
}
@@ -2898,7 +2928,6 @@ int modemask;
char *pathlist;
char *path,*cp;
char c;
- extern int access();
#ifdef __WIN32__
cp = strrchr(argv0,'\\');
@@ -3166,7 +3195,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2){
if( z==0 ) return "";
while( n-- > 0 ){
c = *(zText++);
- if( c=='%' && zText[0]=='d' ){
+ if( c=='%' && n>0 && zText[0]=='d' ){
sprintf(zInt, "%d", p1);
p1 = p2;
strcpy(&z[used], zInt);
@@ -3195,6 +3224,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
for(i=0; i<rp->nrhs; i++) used[i] = 0;
lhsused = 0;
+ if( rp->code==0 ){
+ rp->code = "\n";
+ rp->line = rp->ruleline;
+ }
+
append_str(0,0,0,0);
for(cp=rp->code; *cp; cp++){
if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
@@ -3259,8 +3293,10 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
}
}
}
- cp = append_str(0,0,0,0);
- rp->code = Strsafe(cp);
+ if( rp->code ){
+ cp = append_str(0,0,0,0);
+ rp->code = Strsafe(cp?cp:"");
+ }
}
/*
@@ -3315,7 +3351,7 @@ int mhflag; /* True if generating makeheaders output */
/* Allocate and initialize types[] and allocate stddt[] */
arraysize = lemp->nsymbol * 2;
- types = (char**)malloc( arraysize * sizeof(char*) );
+ types = (char**)calloc( arraysize, sizeof(char*) );
for(i=0; i<arraysize; i++) types[i] = 0;
maxdtlength = 0;
if( lemp->vartype ){
@@ -3396,7 +3432,9 @@ int mhflag; /* True if generating makeheaders output */
fprintf(out," %s yy%d;\n",types[i],i+1); lineno++;
free(types[i]);
}
- fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
+ if( lemp->errsym->useCnt ){
+ fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
+ }
free(stddt);
free(types);
fprintf(out,"} YYMINORTYPE;\n"); lineno++;
@@ -3446,6 +3484,25 @@ static int axset_compare(const void *a, const void *b){
return p2->nAction - p1->nAction;
}
+/*
+** Write text on "out" that describes the rule "rp".
+*/
+static void writeRuleText(FILE *out, struct rule *rp){
+ int j;
+ fprintf(out,"%s ::=", rp->lhs->name);
+ for(j=0; j<rp->nrhs; j++){
+ struct symbol *sp = rp->rhs[j];
+ fprintf(out," %s", sp->name);
+ if( sp->type==MULTITERMINAL ){
+ int k;
+ for(k=1; k<sp->nsubsym; k++){
+ fprintf(out,"|%s",sp->subsym[k]->name);
+ }
+ }
+ }
+}
+
+
/* Generate C source code for the parser */
void ReportTable(lemp, mhflag)
struct lemon *lemp;
@@ -3508,18 +3565,13 @@ int mhflag; /* Output in makeheaders format if true */
lemp->wildcard->index); lineno++;
}
print_stack_union(out,lemp,&lineno,mhflag);
+ fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++;
if( lemp->stacksize ){
- if( atoi(lemp->stacksize)<=0 ){
- ErrorMsg(lemp->filename,0,
-"Illegal stack size: [%s]. The stack size should be an integer constant.",
- lemp->stacksize);
- lemp->errorcnt++;
- lemp->stacksize = "100";
- }
fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++;
}else{
fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++;
}
+ fprintf(out, "#endif\n"); lineno++;
if( mhflag ){
fprintf(out,"#if INTERFACE\n"); lineno++;
}
@@ -3546,8 +3598,10 @@ int mhflag; /* Output in makeheaders format if true */
}
fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++;
fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
- fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
- fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+ if( lemp->errsym->useCnt ){
+ fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
+ fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+ }
if( lemp->has_fallback ){
fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
}
@@ -3566,7 +3620,7 @@ int mhflag; /* Output in makeheaders format if true */
*/
/* Compute the actions on all states and count them up */
- ax = malloc( sizeof(ax[0])*lemp->nstate*2 );
+ ax = calloc(lemp->nstate*2, sizeof(ax[0]));
if( ax==0 ){
fprintf(stderr,"malloc failed\n");
exit(1);
@@ -3623,7 +3677,7 @@ int mhflag; /* Output in makeheaders format if true */
n = acttab_size(pActtab);
for(i=j=0; i<n; i++){
int action = acttab_yyaction(pActtab, i);
- if( action<0 ) action = lemp->nsymbol + lemp->nrule + 2;
+ if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
if( j==0 ) fprintf(out," /* %5d */ ", i);
fprintf(out, " %4d,", action);
if( j==9 || i==n-1 ){
@@ -3746,17 +3800,8 @@ int mhflag; /* Output in makeheaders format if true */
*/
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
assert( rp->index==i );
- fprintf(out," /* %3d */ \"%s ::=", i, rp->lhs->name);
- for(j=0; j<rp->nrhs; j++){
- struct symbol *sp = rp->rhs[j];
- fprintf(out," %s", sp->name);
- if( sp->type==MULTITERMINAL ){
- int k;
- for(k=1; k<sp->nsubsym; k++){
- fprintf(out,"|%s",sp->subsym[k]->name);
- }
- }
- }
+ fprintf(out," /* %3d */ \"", i);
+ writeRuleText(out, rp);
fprintf(out,"\",\n"); lineno++;
}
tplt_xfer(lemp->name,in,out,&lineno);
@@ -3769,7 +3814,8 @@ int mhflag; /* Output in makeheaders format if true */
for(i=0; i<lemp->nsymbol; i++){
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type!=TERMINAL ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
}
for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
if( i<lemp->nsymbol ){
@@ -3783,7 +3829,8 @@ int mhflag; /* Output in makeheaders format if true */
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type==TERMINAL ||
sp->index<=0 || sp->destructor!=0 ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
dflt_sp = sp;
}
if( dflt_sp!=0 ){
@@ -3794,7 +3841,8 @@ int mhflag; /* Output in makeheaders format if true */
for(i=0; i<lemp->nsymbol; i++){
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
/* Combine duplicate destructors into a single case */
for(j=i+1; j<lemp->nsymbol; j++){
@@ -3802,7 +3850,8 @@ int mhflag; /* Output in makeheaders format if true */
if( sp2 && sp2->type!=TERMINAL && sp2->destructor
&& sp2->dtnum==sp->dtnum
&& strcmp(sp->destructor,sp2->destructor)==0 ){
- fprintf(out," case %d:\n",sp2->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp2->index, sp2->name); lineno++;
sp2->destructor = 0;
}
}
@@ -3828,15 +3877,19 @@ int mhflag; /* Output in makeheaders format if true */
/* Generate code which execution during each REDUCE action */
for(rp=lemp->rule; rp; rp=rp->next){
- if( rp->code ) translate_code(lemp, rp);
+ translate_code(lemp, rp);
}
for(rp=lemp->rule; rp; rp=rp->next){
struct rule *rp2;
if( rp->code==0 ) continue;
- fprintf(out," case %d:\n",rp->index); lineno++;
+ fprintf(out," case %d: /* ", rp->index);
+ writeRuleText(out, rp);
+ fprintf(out, " */\n"); lineno++;
for(rp2=rp->next; rp2; rp2=rp2->next){
if( rp2->code==rp->code ){
- fprintf(out," case %d:\n",rp2->index); lineno++;
+ fprintf(out," case %d: /* ", rp2->index);
+ writeRuleText(out, rp2);
+ fprintf(out," */\n"); lineno++;
rp2->code = 0;
}
}
@@ -3928,6 +3981,7 @@ struct lemon *lemp;
}
if( ap->type!=REDUCE ) continue;
rp = ap->x.rp;
+ if( rp->lhsStart ) continue;
if( rp==rbest ) continue;
n = 1;
for(ap2=ap->next; ap2; ap2=ap2->next){
@@ -4036,13 +4090,11 @@ int n;
/* Allocate a new set */
char *SetNew(){
char *s;
- int i;
- s = (char*)malloc( size );
+ s = (char*)calloc( size, 1);
if( s==0 ){
extern void memory_error();
memory_error();
}
- for(i=0; i<size; i++) s[i] = 0;
return s;
}
@@ -4060,6 +4112,7 @@ char *s;
int e;
{
int rv;
+ assert( e>=0 && e<size );
rv = s[e];
s[e] = 1;
return !rv;
@@ -4249,7 +4302,7 @@ char *x;
sp = Symbol_find(x);
if( sp==0 ){
- sp = (struct symbol *)malloc( sizeof(struct symbol) );
+ sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
MemoryCheck(sp);
sp->name = Strsafe(x);
sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
@@ -4258,11 +4311,13 @@ char *x;
sp->prec = -1;
sp->assoc = UNK;
sp->firstset = 0;
- sp->lambda = B_FALSE;
+ sp->lambda = LEMON_FALSE;
sp->destructor = 0;
sp->datatype = 0;
+ sp->useCnt = 0;
Symbol_insert(sp,sp->name);
}
+ sp->useCnt++;
return sp;
}
@@ -4432,7 +4487,7 @@ struct symbol **Symbol_arrayof()
int i,size;
if( x2a==0 ) return 0;
size = x2a->count;
- array = (struct symbol **)malloc( sizeof(struct symbol *)*size );
+ array = (struct symbol **)calloc(size, sizeof(struct symbol *));
if( array ){
for(i=0; i<size; i++) array[i] = x2a->tbl[i].data;
}
@@ -4483,7 +4538,7 @@ struct config *a;
struct state *State_new()
{
struct state *new;
- new = (struct state *)malloc( sizeof(struct state) );
+ new = (struct state *)calloc(1, sizeof(struct state) );
MemoryCheck(new);
return new;
}
diff --git a/ext/pdo_sqlite/sqlite/tool/lempar.c b/ext/pdo_sqlite/sqlite/tool/lempar.c
index a18c43a24d..cca91ad252 100644
--- a/ext/pdo_sqlite/sqlite/tool/lempar.c
+++ b/ext/pdo_sqlite/sqlite/tool/lempar.c
@@ -44,7 +44,8 @@
** This is typically a union of many types, one of
** which is ParseTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
** ParseARG_SDECL A static variable declaration for the %extra_argument
** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser
@@ -152,7 +153,12 @@ struct yyParser {
int yyidx; /* Index of top element in stack */
int yyerrcnt; /* Shifts left before out of the error */
ParseARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
};
typedef struct yyParser yyParser;
@@ -204,21 +210,29 @@ static const char *const yyRuleName[] = {
};
#endif /* NDEBUG */
+
+#if YYSTACKDEPTH<=0
/*
-** This function returns the symbolic name associated with a token
-** value.
+** Try to increase the size of the parser stack.
*/
-const char *ParseTokenName(int tokenType){
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
#endif
+ }
}
+#endif
/*
** This function allocates a new parser.
@@ -237,6 +251,9 @@ void *ParseAlloc(void *(*mallocProc)(size_t)){
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
+#if YYSTACKDEPTH<=0
+ yyGrowStack(pParser);
+#endif
}
return pParser;
}
@@ -308,6 +325,9 @@ void ParseFree(
yyParser *pParser = (yyParser*)p;
if( pParser==0 ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
(*freeProc)((void*)pParser);
}
@@ -329,9 +349,7 @@ static int yy_find_shift_action(
if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
if( iLookAhead>0 ){
@@ -382,21 +400,32 @@ static int yy_find_reduce_action(
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
- /* int stateno = pParser->yystack[pParser->yyidx].stateno; */
-
- if( stateno>YY_REDUCE_MAX ||
- (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( stateno<=YY_REDUCE_MAX );
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
+ assert( i>=0 && i<YY_SZ_ACTTAB );
+ assert( yy_lookahead[i]==iLookAhead );
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ ParseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
}
/*
@@ -410,21 +439,20 @@ static void yy_shift(
){
yyStackEntry *yytos;
yypParser->yyidx++;
+#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
- ParseARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
+ yyStackOverflow(yypParser, yypMinor);
+ return;
}
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = yyNewState;
yytos->major = yyMajor;
@@ -476,7 +504,6 @@ static void yy_reduce(
}
#endif /* NDEBUG */
-#ifndef NDEBUG
/* Silence complaints from purify about yygotominor being uninitialized
** in some cases when it is copied into the stack after the following
** switch. yygotominor is uninitialized when a rule reduces that does
@@ -484,9 +511,15 @@ static void yy_reduce(
** value of the nonterminal uninitialized is utterly harmless as long
** as the value is never used. So really the only thing this code
** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
*/
memset(&yygotominor, 0, sizeof(yygotominor));
-#endif
+
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -520,7 +553,8 @@ static void yy_reduce(
{
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}
- }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
yy_accept(yypParser);
}
}
@@ -605,13 +639,21 @@ void Parse(
YYMINORTYPE yyminorunion;
int yyact; /* The parser action. */
int yyendofinput; /* True if we are at the end of input */
+#ifdef YYERRORSYMBOL
int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
yyParser *yypParser; /* The parser */
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
- /* if( yymajor==0 ) return; // not sure why this was here... */
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ memset(&yyminorunion, 0, sizeof(yyminorunion));
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
@@ -630,17 +672,17 @@ void Parse(
do{
yyact = yy_find_shift_action(yypParser,yymajor);
if( yyact<YYNSTATE ){
+ assert( !yyendofinput ); /* Impossible to shift the $ token */
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
- if( yyendofinput && yypParser->yyidx>=0 ){
- yymajor = 0;
- }else{
- yymajor = YYNOCODE;
- }
+ yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){
yy_reduce(yypParser,yyact-YYNSTATE);
- }else if( yyact == YY_ERROR_ACTION ){
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
int yymx;
+#endif
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
@@ -721,9 +763,6 @@ void Parse(
}
yymajor = YYNOCODE;
#endif
- }else{
- yy_accept(yypParser);
- yymajor = YYNOCODE;
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
return;
diff --git a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
index 3301a40e97..e5adb82731 100644
--- a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
+++ b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
@@ -8,6 +8,25 @@
#include <stdlib.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"
+ "** $Header$\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 as in a hash
** table composed of instances of the following structure.
*/
@@ -21,6 +40,7 @@ struct 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 */
@@ -95,7 +115,8 @@ struct Keyword {
#else
# define TRIGGER 0x00002000
#endif
-#ifdef SQLITE_OMIT_VACUUM
+#if defined(SQLITE_OMIT_AUTOVACUUM) && \
+ (defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH))
# define VACUUM 0
#else
# define VACUUM 0x00004000
@@ -110,6 +131,11 @@ struct Keyword {
#else
# define VTAB 0x00010000
#endif
+#ifdef SQLITE_OMIT_AUTOVACUUM
+# define AUTOVACUUM 0
+#else
+# define AUTOVACUUM 0x00020000
+#endif
/*
** These are the keywords
@@ -198,8 +224,10 @@ static Keyword aKeywordTable[] = {
{ "OR", "TK_OR", ALWAYS },
{ "ORDER", "TK_ORDER", ALWAYS },
{ "OUTER", "TK_JOIN_KW", ALWAYS },
+ { "PLAN", "TK_PLAN", EXPLAIN },
{ "PRAGMA", "TK_PRAGMA", PRAGMA },
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
+ { "QUERY", "TK_QUERY", EXPLAIN },
{ "RAISE", "TK_RAISE", TRIGGER },
{ "REFERENCES", "TK_REFERENCES", FKEY },
{ "REGEXP", "TK_LIKE_KW", ALWAYS },
@@ -212,7 +240,6 @@ static Keyword aKeywordTable[] = {
{ "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 },
@@ -233,7 +260,7 @@ static Keyword aKeywordTable[] = {
};
/* Number of keywords */
-static int NKEYWORD = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
+static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
/* An array to map all upper-case characters into their corresponding
** lower-case character.
@@ -272,7 +299,10 @@ static int keywordCompare1(const void *a, const void *b){
static int keywordCompare2(const void *a, const void *b){
const Keyword *pA = (Keyword*)a;
const Keyword *pB = (Keyword*)b;
- int n = strcmp(pA->zName, pB->zName);
+ int n = pB->longestSuffix - pA->longestSuffix;
+ if( n==0 ){
+ n = strcmp(pA->zName, pB->zName);
+ }
return n;
}
static int keywordCompare3(const void *a, const void *b){
@@ -287,7 +317,7 @@ static int keywordCompare3(const void *a, const void *b){
*/
static Keyword *findById(int id){
int i;
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
if( aKeywordTable[i].id==id ) break;
}
return &aKeywordTable[i];
@@ -302,34 +332,36 @@ int main(int argc, char **argv){
int bestSize, bestCount;
int count;
int nChar;
- int aHash[1000]; /* 1000 is much bigger than NKEYWORD */
+ int totalLen = 0;
+ 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++){
+ for(i=j=0; i<nKeyword; i++){
if( aKeywordTable[i].mask==0 ) continue;
if( j<i ){
aKeywordTable[j] = aKeywordTable[i];
}
j++;
}
- NKEYWORD = j;
+ nKeyword = j;
/* Fill in the lengths of strings and hashes for all entries. */
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
p->len = strlen(p->zName);
- p->hash = (UpperToLower[p->zName[0]]*4) ^
- (UpperToLower[p->zName[p->len-1]]*3) ^ p->len;
+ totalLen += p->len;
+ p->hash = (UpperToLower[(int)p->zName[0]]*4) ^
+ (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len;
p->id = i+1;
}
/* Sort the table from shortest to longest keyword */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare1);
+ qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1);
/* Look for short keywords embedded in longer keywords */
- for(i=NKEYWORD-2; i>=0; i--){
+ for(i=nKeyword-2; i>=0; i--){
Keyword *p = &aKeywordTable[i];
- for(j=NKEYWORD-1; j>i && p->substrId==0; j--){
+ for(j=nKeyword-1; j>i && p->substrId==0; j--){
Keyword *pOther = &aKeywordTable[j];
if( pOther->substrId ) continue;
if( pOther->len<=p->len ) continue;
@@ -343,18 +375,35 @@ int main(int argc, char **argv){
}
}
- /* Sort the table into alphabetical order */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare2);
+ /* 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++){
+ 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++){
+ for(j=i+1; j<nKeyword; j++){
Keyword *pOther = &aKeywordTable[j];
if( pOther->offset>0 || pOther->substrId ) continue;
if( pOther->len<=k ) continue;
@@ -371,7 +420,7 @@ int main(int argc, char **argv){
}
}
}
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ){
p->offset = findById(p->substrId)->offset + p->substrOffset;
@@ -379,15 +428,15 @@ int main(int argc, char **argv){
}
/* Sort the table by offset */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare3);
+ 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++){
+ 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++){
+ for(j=0; j<nKeyword; j++){
h = aKeywordTable[j].hash % i;
aHash[h] *= 2;
aHash[h]++;
@@ -401,18 +450,21 @@ int main(int argc, char **argv){
/* Compute the hash */
for(i=0; i<bestSize; i++) aHash[i] = 0;
- for(i=0; i<NKEYWORD; i++){
+ 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){\n");
+ printf(" /* zText[] encodes %d bytes of keywords in %d bytes */\n",
+ totalLen + nKeyword, nChar+1 );
printf(" static const char zText[%d] =\n", nChar+1);
- for(i=j=0; i<NKEYWORD; i++){
+ for(i=j=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ) continue;
if( j==0 ) printf(" \"");
@@ -437,8 +489,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aNext[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ 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++;
@@ -449,8 +501,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aLen[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ 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++;
@@ -461,8 +513,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned short int aOffset[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ 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++;
@@ -473,8 +525,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aCode[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ 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)), "");
diff --git a/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl b/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl
new file mode 100644
index 0000000000..e7befd8fc4
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl
@@ -0,0 +1,278 @@
+#!/usr/bin/tclsh
+#
+# To build a single huge source file holding all of SQLite (or at
+# least the core components - the test harness, shell, and TCL
+# interface are omitted.) first do
+#
+# make target_source
+#
+# The make target above moves all of the source code files into
+# a subdirectory named "tsrc". (This script expects to find the files
+# there and will not work if they are not found.) There are a few
+# generated C code files that are also added to the tsrc directory.
+# For example, the "parse.c" and "parse.h" files to implement the
+# the parser are derived from "parse.y" using lemon. And the
+# "keywordhash.h" files is generated by a program named "mkkeywordhash".
+#
+# After the "tsrc" directory has been created and populated, run
+# this script:
+#
+# tclsh mksqlite3c.tcl
+#
+# The amalgamated SQLite code will be written into sqlite3.c
+#
+
+# Begin by reading the "sqlite3.h" header file. Count the number of lines
+# in this file and extract the version number. That information will be
+# needed in order to generate the header of the amalgamation.
+#
+if {[lsearch $argv --nostatic]>=0} {
+ set addstatic 0
+} else {
+ set addstatic 1
+}
+set in [open tsrc/sqlite3.h]
+set cnt 0
+set VERSION ?????
+while {![eof $in]} {
+ set line [gets $in]
+ if {$line=="" && [eof $in]} break
+ incr cnt
+ regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
+}
+close $in
+
+# Open the output file and write a header comment at the beginning
+# of the file.
+#
+set out [open sqlite3.c w]
+set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
+puts $out [subst \
+{/******************************************************************************
+** This file is an amalgamation of many separate C source files from SQLite
+** version $VERSION. By combining all the individual C code files into this
+** single large file, the entire code can be compiled as a one translation
+** unit. This allows many compilers to do optimizations that would not be
+** possible if the files were compiled separately. Performance improvements
+** of 5% are more are commonly seen when SQLite is compiled as a single
+** translation unit.
+**
+** This file is all you need to compile SQLite. To use SQLite in other
+** programs, you need this file and the "sqlite3.h" header file that defines
+** the programming interface to the SQLite library. (If you do not have
+** the "sqlite3.h" header file at hand, you will find a copy in the first
+** $cnt lines past this header comment.) Additional code files may be
+** needed if you want a wrapper to interface SQLite with your choice of
+** programming language. The code for the "sqlite3" command-line shell
+** is also in a separate file. This file contains only code for the core
+** SQLite library.
+**
+** This amalgamation was generated on $today.
+*/
+#define SQLITE_CORE 1
+#define SQLITE_AMALGAMATION 1}]
+if {$addstatic} {
+ puts $out \
+{#ifndef SQLITE_PRIVATE
+# define SQLITE_PRIVATE static
+#endif
+#ifndef SQLITE_API
+# define SQLITE_API
+#endif}
+}
+
+# These are the header files used by SQLite. The first time any of these
+# files are seen in a #include statement in the C code, include the complete
+# text of the file in-line. The file only needs to be included once.
+#
+foreach hdr {
+ btree.h
+ btreeInt.h
+ fts3.h
+ fts3_hash.h
+ fts3_tokenizer.h
+ hash.h
+ keywordhash.h
+ mutex.h
+ opcodes.h
+ os_common.h
+ os.h
+ os_os2.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ sqlite3.h
+ sqliteInt.h
+ sqliteLimit.h
+ vdbe.h
+ vdbeInt.h
+} {
+ set available_hdr($hdr) 1
+}
+set available_hdr(sqliteInt.h) 0
+
+# 78 stars used for comment formatting.
+set s78 \
+{*****************************************************************************}
+
+# Insert a comment into the code
+#
+proc section_comment {text} {
+ global out s78
+ set n [string length $text]
+ set nstar [expr {60 - $n}]
+ set stars [string range $s78 0 $nstar]
+ puts $out "/************** $text $stars/"
+}
+
+# Read the source file named $filename and write it into the
+# sqlite3.c output file. If any #include statements are seen,
+# process them approprately.
+#
+proc copy_file {filename} {
+ global seen_hdr available_hdr out addstatic
+ set tail [file tail $filename]
+ section_comment "Begin file $tail"
+ set in [open $filename r]
+ set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
+ set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \*?(sqlite3[_a-zA-Z0-9]+)\(}
+ if {[file extension $filename]==".h"} {
+ set declpattern " *$declpattern"
+ }
+ set declpattern ^$declpattern
+ while {![eof $in]} {
+ set line [gets $in]
+ if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
+ if {[info exists available_hdr($hdr)]} {
+ if {$available_hdr($hdr)} {
+ if {$hdr!="os_common.h"} {
+ set available_hdr($hdr) 0
+ }
+ section_comment "Include $hdr in the middle of $tail"
+ copy_file tsrc/$hdr
+ section_comment "Continuing where we left off in $tail"
+ }
+ } elseif {![info exists seen_hdr($hdr)]} {
+ set seen_hdr($hdr) 1
+ puts $out $line
+ }
+ } elseif {[regexp {^#ifdef __cplusplus} $line]} {
+ puts $out "#if 0"
+ } elseif {[regexp {^#line} $line]} {
+ # Skip #line directives.
+ } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} {
+ if {[regexp $declpattern $line all funcname]} {
+ # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
+ # so that linkage can be modified at compile-time.
+ if {[regexp {^sqlite3_} $funcname]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out "SQLITE_PRIVATE $line"
+ }
+ } elseif {[regexp $varpattern $line all varname]} {
+ # Add the SQLITE_PRIVATE before variable declarations or
+ # definitions for internal use
+ if {![regexp {^sqlite3_} $varname]} {
+ regsub {^extern } $line {} line
+ puts $out "SQLITE_PRIVATE $line"
+ } elseif {![regexp {^SQLITE_EXTERN} $line]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out $line
+ }
+ } elseif {[regexp {^void \(\*sqlite3_io_trace\)} $line]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out $line
+ }
+ } else {
+ puts $out $line
+ }
+ }
+ close $in
+ section_comment "End of $tail"
+}
+
+
+# Process the source files. Process files containing commonly
+# used subroutines first in order to help the compiler find
+# inlining opportunities.
+#
+foreach file {
+ sqliteInt.h
+
+ date.c
+ os.c
+
+ fault.c
+ mem1.c
+ mem2.c
+ mem3.c
+ mutex.c
+ mutex_os2.c
+ mutex_unix.c
+ mutex_w32.c
+ malloc.c
+ printf.c
+ random.c
+ utf.c
+ util.c
+ hash.c
+ opcodes.c
+
+ os_os2.c
+ os_unix.c
+ os_win.c
+
+ pager.c
+
+ btmutex.c
+ btree.c
+
+ vdbefifo.c
+ vdbemem.c
+ vdbeaux.c
+ vdbeapi.c
+ vdbe.c
+ vdbeblob.c
+ journal.c
+
+ expr.c
+ alter.c
+ analyze.c
+ attach.c
+ auth.c
+ build.c
+ callback.c
+ delete.c
+ func.c
+ insert.c
+ legacy.c
+ loadext.c
+ pragma.c
+ prepare.c
+ select.c
+ table.c
+ trigger.c
+ update.c
+ vacuum.c
+ vtab.c
+ where.c
+
+ parse.c
+
+ tokenize.c
+ complete.c
+
+ main.c
+
+ fts3.c
+ fts3_hash.c
+ fts3_porter.c
+ fts3_tokenizer.c
+ fts3_tokenizer1.c
+} {
+ copy_file tsrc/$file
+}
+
+close $out
diff --git a/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl b/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl
new file mode 100644
index 0000000000..cacd7cbe18
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl
@@ -0,0 +1,145 @@
+#!/usr/bin/tclsh
+#
+# To build a single huge source file holding all of SQLite (or at
+# least the core components - the test harness, shell, and TCL
+# interface are omitted.) first do
+#
+# make target_source
+#
+# The make target above moves all of the source code files into
+# a subdirectory named "tsrc". (This script expects to find the files
+# there and will not work if they are not found.) There are a few
+# generated C code files that are also added to the tsrc directory.
+# For example, the "parse.c" and "parse.h" files to implement the
+# the parser are derived from "parse.y" using lemon. And the
+# "keywordhash.h" files is generated by a program named "mkkeywordhash".
+#
+# After the "tsrc" directory has been created and populated, run
+# this script:
+#
+# tclsh mksqlite3c.tcl
+#
+# The amalgamated SQLite code will be written into sqlite3.c
+#
+
+# Begin by reading the "sqlite3.h" header file. Count the number of lines
+# in this file and extract the version number. That information will be
+# needed in order to generate the header of the amalgamation.
+#
+set in [open tsrc/sqlite3.h]
+set cnt 0
+set VERSION ?????
+while {![eof $in]} {
+ set line [gets $in]
+ if {$line=="" && [eof $in]} break
+ incr cnt
+ regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
+}
+close $in
+
+# Open the output file and write a header comment at the beginning
+# of the file.
+#
+set out [open sqlite3internal.h w]
+set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
+puts $out [subst \
+{/******************************************************************************
+** This file is an amalgamation of many private header files from SQLite
+** version $VERSION.
+*/}]
+
+# These are the header files used by SQLite. The first time any of these
+# files are seen in a #include statement in the C code, include the complete
+# text of the file in-line. The file only needs to be included once.
+#
+foreach hdr {
+ btree.h
+ btreeInt.h
+ hash.h
+ keywordhash.h
+ opcodes.h
+ os_common.h
+ os.h
+ os_os2.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ sqlite3.h
+ sqliteInt.h
+ sqliteLimit.h
+ vdbe.h
+ vdbeInt.h
+} {
+ set available_hdr($hdr) 1
+}
+
+# 78 stars used for comment formatting.
+set s78 \
+{*****************************************************************************}
+
+# Insert a comment into the code
+#
+proc section_comment {text} {
+ global out s78
+ set n [string length $text]
+ set nstar [expr {60 - $n}]
+ set stars [string range $s78 0 $nstar]
+ puts $out "/************** $text $stars/"
+}
+
+# Read the source file named $filename and write it into the
+# sqlite3.c output file. If any #include statements are seen,
+# process them approprately.
+#
+proc copy_file {filename} {
+ global seen_hdr available_hdr out
+ set tail [file tail $filename]
+ section_comment "Begin file $tail"
+ set in [open $filename r]
+ while {![eof $in]} {
+ set line [gets $in]
+ if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
+ if {[info exists available_hdr($hdr)]} {
+ if {$available_hdr($hdr)} {
+ section_comment "Include $hdr in the middle of $tail"
+ copy_file tsrc/$hdr
+ section_comment "Continuing where we left off in $tail"
+ }
+ } elseif {![info exists seen_hdr($hdr)]} {
+ set seen_hdr($hdr) 1
+ puts $out $line
+ }
+ } elseif {[regexp {^#ifdef __cplusplus} $line]} {
+ puts $out "#if 0"
+ } elseif {[regexp {^#line} $line]} {
+ # Skip #line directives.
+ } else {
+ puts $out $line
+ }
+ }
+ close $in
+ section_comment "End of $tail"
+}
+
+
+# Process the source files. Process files containing commonly
+# used subroutines first in order to help the compiler find
+# inlining opportunities.
+#
+foreach file {
+ sqliteInt.h
+ sqlite3.h
+ btree.h
+ hash.h
+ os.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ vdbe.h
+} {
+ if {$available_hdr($file)} {
+ copy_file tsrc/$file
+ }
+}
+
+close $out
diff --git a/ext/pdo_sqlite/sqlite/tool/omittest.tcl b/ext/pdo_sqlite/sqlite/tool/omittest.tcl
new file mode 100644
index 0000000000..baf69c3151
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/omittest.tcl
@@ -0,0 +1,176 @@
+
+set rcsid {$Id: omittest.tcl,v 1.2 2008-03-07 10:55:14 scottmac Exp $}
+
+# Documentation for this script. This may be output to stderr
+# if the script is invoked incorrectly.
+set ::USAGE_MESSAGE {
+This Tcl script is used to test the various compile time options
+available for omitting code (the SQLITE_OMIT_xxx options). It
+should be invoked as follows:
+
+ <script> ?-makefile PATH-TO-MAKEFILE?
+
+The default value for ::MAKEFILE is "../Makefile.linux.gcc".
+
+This script builds the testfixture program and runs the SQLite test suite
+once with each SQLITE_OMIT_ option defined and then once with all options
+defined together. Each run is performed in a seperate directory created
+as a sub-directory of the current directory by the script. The output
+of the build is saved in <sub-directory>/build.log. The output of the
+test-suite is saved in <sub-directory>/test.log.
+
+Almost any SQLite makefile (except those generated by configure - see below)
+should work. The following properties are required:
+
+ * The makefile should support the "testfixture" target.
+ * The makefile should support the "test" target.
+ * The makefile should support the variable "OPTS" as a way to pass
+ options from the make command line to lemon and the C compiler.
+
+More precisely, the following two invocations must be supported:
+
+ make -f $::MAKEFILE testfixture OPTS="-DSQLITE_OMIT_ALTERTABLE=1"
+ make -f $::MAKEFILE test
+
+Makefiles generated by the sqlite configure program cannot be used as
+they do not respect the OPTS variable.
+}
+
+
+# Build a testfixture executable and run quick.test using it. The first
+# parameter is the name of the directory to create and use to run the
+# test in. The second parameter is a list of OMIT symbols to define
+# when doing so. For example:
+#
+# run_quick_test /tmp/testdir {SQLITE_OMIT_TRIGGER SQLITE_OMIT_VIEW}
+#
+#
+proc run_quick_test {dir omit_symbol_list} {
+ # Compile the value of the OPTS Makefile variable.
+ set opts "-DSQLITE_MEMDEBUG=2 -DSQLITE_DEBUG -DOS_UNIX"
+ foreach sym $omit_symbol_list {
+ append opts " -D${sym}=1"
+ }
+
+ # Create the directory and do the build. If an error occurs return
+ # early without attempting to run the test suite.
+ file mkdir $dir
+ puts -nonewline "Building $dir..."
+ flush stdout
+ set rc [catch {
+ exec make -C $dir -f $::MAKEFILE testfixture OPTS=$opts >& $dir/build.log
+ }]
+ if {$rc} {
+ puts "No good. See $dir/build.log."
+ return
+ } else {
+ puts "Ok"
+ }
+
+ # Create an empty file "$dir/sqlite3". This is to trick the makefile out
+ # of trying to build the sqlite shell. The sqlite shell won't build
+ # with some of the OMIT options (i.e OMIT_COMPLETE).
+ if {![file exists $dir/sqlite3]} {
+ set wr [open $dir/sqlite3 w]
+ puts $wr "dummy"
+ close $wr
+ }
+
+ # Run the test suite.
+ puts -nonewline "Testing $dir..."
+ flush stdout
+ set rc [catch {
+ exec make -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log
+ }]
+ if {$rc} {
+ puts "No good. See $dir/test.log."
+ } else {
+ puts "Ok"
+ }
+}
+
+
+# This proc processes the command line options passed to this script.
+# Currently the only option supported is "-makefile", default
+# "../Makefile.linux-gcc". Set the ::MAKEFILE variable to the value of this
+# option.
+#
+proc process_options {argv} {
+ set ::MAKEFILE ../Makefile.linux-gcc ;# Default value
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ switch -- [lindex $argv $i] {
+ -makefile {
+ incr i
+ set ::MAKEFILE [lindex $argv $i]
+ }
+
+ default {
+ puts stderr [string trim $::USAGE_MESSAGE]
+ exit -1
+ }
+ }
+ set ::MAKEFILE [file normalize $::MAKEFILE]
+ }
+}
+
+# Main routine.
+#
+
+proc main {argv} {
+ # List of SQLITE_OMIT_XXX symbols supported by SQLite.
+ set ::SYMBOLS [list \
+ SQLITE_OMIT_ALTERTABLE \
+ SQLITE_OMIT_AUTHORIZATION \
+ SQLITE_OMIT_AUTOINCREMENT \
+ SQLITE_OMIT_AUTOVACUUM \
+ SQLITE_OMIT_BLOB_LITERAL \
+ SQLITE_OMIT_COMPLETE \
+ SQLITE_OMIT_COMPOUND_SELECT \
+ SQLITE_OMIT_CONFLICT_CLAUSE \
+ SQLITE_OMIT_DATETIME_FUNCS \
+ SQLITE_OMIT_EXPLAIN \
+ SQLITE_OMIT_FLOATING_POINT \
+ SQLITE_OMIT_FOREIGN_KEY \
+ SQLITE_OMIT_INCRBLOB \
+ SQLITE_OMIT_INTEGRITY_CHECK \
+ SQLITE_OMIT_MEMORYDB \
+ SQLITE_OMIT_PAGER_PRAGMAS \
+ SQLITE_OMIT_PRAGMA \
+ SQLITE_OMIT_PROGRESS_CALLBACK \
+ SQLITE_OMIT_REINDEX \
+ SQLITE_OMIT_SCHEMA_PRAGMAS \
+ SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \
+ SQLITE_OMIT_SUBQUERY \
+ SQLITE_OMIT_TCL_VARIABLE \
+ SQLITE_OMIT_TRIGGER \
+ SQLITE_OMIT_UTF16 \
+ SQLITE_OMIT_VACUUM \
+ SQLITE_OMIT_VIEW \
+ SQLITE_OMIT_VIRTUALTABLE \
+ ]
+
+ # Process any command line options.
+ process_options $argv
+
+ # First try a test with all OMIT symbols except SQLITE_OMIT_FLOATING_POINT
+ # and SQLITE_OMIT_PRAGMA defined. The former doesn't work (causes segfaults)
+ # and the latter is currently incompatible with the test suite (this should
+ # be fixed, but it will be a lot of work).
+ set allsyms [list]
+ foreach s $::SYMBOLS {
+ if {$s!="SQLITE_OMIT_FLOATING_POINT" && $s!="SQLITE_OMIT_PRAGMA"} {
+ lappend allsyms $s
+ }
+ }
+ run_quick_test test_OMIT_EVERYTHING $allsyms
+
+ # Now try one quick.test with each of the OMIT symbols defined. Included
+ # are the OMIT_FLOATING_POINT and OMIT_PRAGMA symbols, even though we
+ # know they will fail. It's good to be reminded of this from time to time.
+ foreach sym $::SYMBOLS {
+ set dirname "test_[string range $sym 7 end]"
+ run_quick_test $dirname $sym
+ }
+}
+
+main $argv
diff --git a/ext/pdo_sqlite/sqlite/tool/soak1.tcl b/ext/pdo_sqlite/sqlite/tool/soak1.tcl
new file mode 100644
index 0000000000..7a78b8d7dd
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/soak1.tcl
@@ -0,0 +1,103 @@
+#!/usr/bin/tclsh
+#
+# Usage:
+#
+# tclsh soak1.tcl local-makefile.mk ?target? ?scenario?
+#
+# This generates many variations on local-makefile.mk (by modifing
+# the OPT = lines) and runs them will fulltest, one by one. The
+# constructed makefiles are named "soak1.mk".
+#
+# If ?target? is provided, that is the makefile target that is run.
+# The default is "fulltest"
+#
+# If ?scenario? is provided, it is the name of a single scenario to
+# be run. All other scenarios are skipped.
+#
+set localmake [lindex $argv 0]
+set target [lindex $argv 1]
+set scene [lindex $argv 2]
+if {$target==""} {set target fulltest}
+if {$scene==""} {set scene all}
+
+set in [open $localmake]
+set maketxt [read $in]
+close $in
+regsub -all {\\\n} $maketxt {} maketxt
+#set makefilename "soak1-[expr {int(rand()*1000000000)}].mk"
+set makefilename "soak1.mk"
+
+# Generate a makefile
+#
+proc generate_makefile {pattern} {
+ global makefilename maketxt
+ set out [open $makefilename w]
+ set seen_opt 0
+ foreach line [split $maketxt \n] {
+ if {[regexp {^ *#? *OPTS[ =+]} $line]} {
+ if {!$seen_opt} {
+ puts $out "OPTS += -DSQLITE_NO_SYNC=1"
+ foreach x $pattern {
+ puts $out "OPTS += -D$x"
+ }
+ set seen_opt 1
+ }
+ } else {
+ puts $out $line
+ }
+ }
+ close $out
+}
+
+# Run a test
+#
+proc scenario {id title pattern} {
+ global makefilename target scene
+ if {$scene!="all" && $scene!=$id && $scene!=$title} return
+ puts "**************** $title ***************"
+ generate_makefile $pattern
+ exec make -f $makefilename clean >@stdout 2>@stdout
+ exec make -f $makefilename $target >@stdout 2>@stdout
+}
+
+###############################################################################
+# Add new scenarios here
+#
+scenario 0 {Default} {}
+scenario 1 {Debug} {
+ SQLITE_DEBUG=1
+ SQLITE_MEMDEBUG=1
+}
+scenario 2 {Everything} {
+ SQLITE_DEBUG=1
+ SQLITE_MEMDEBUG=1
+ SQLITE_ENABLE_MEMORY_MANAGEMENT=1
+ SQLITE_ENABLE_COLUMN_METADATA=1
+ SQLITE_ENABLE_LOAD_EXTENSION=1 HAVE_DLOPEN=1
+ SQLITE_ENABLE_MEMORY_MANAGEMENT=1
+}
+scenario 3 {Customer-1} {
+ SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1
+ THREADSAFE=1 OS_UNIX=1
+ SQLITE_DISABLE_LFS=1
+ SQLITE_DEFAULT_AUTOVACUUM=1
+ SQLITE_DEFAULT_PAGE_SIZE=1024
+ SQLITE_MAX_PAGE_SIZE=4096
+ SQLITE_DEFAULT_CACHE_SIZE=64
+ SQLITE_DEFAULT_TEMP_CACHE_SIZE=32
+ TEMP_STORE=3
+ SQLITE_OMIT_PROGRESS_CALLBACK=1
+ SQLITE_OMIT_LOAD_EXTENSION=1
+ SQLITE_OMIT_VIRTUALTABLE=1
+ SQLITE_ENABLE_IOTRACE=1
+}
+scenario 4 {Small-Cache} {
+ SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1
+ THREADSAFE=1 OS_UNIX=1
+ SQLITE_DEFAULT_AUTOVACUUM=1
+ SQLITE_DEFAULT_PAGE_SIZE=1024
+ SQLITE_MAX_PAGE_SIZE=2048
+ SQLITE_DEFAULT_CACHE_SIZE=13
+ SQLITE_DEFAULT_TEMP_CACHE_SIZE=11
+ TEMP_STORE=1
+}
diff --git a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
index c0fe5b5d87..3718357cbb 100644
--- a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
+++ b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
@@ -26,6 +26,10 @@ if {[file size $file_to_analyze]<512} {
exit 1
}
+# Maximum distance between pages before we consider it a "gap"
+#
+set MAXGAP 3
+
# Open the database
#
sqlite3 db [lindex $argv 0]
@@ -53,12 +57,17 @@ set tabledef\
ovfl_pages int, -- Number of overflow pages used
int_unused int, -- Number of unused bytes on interior pages
leaf_unused int, -- Number of unused bytes on primary pages
- ovfl_unused int -- Number of unused bytes on overflow pages
+ ovfl_unused int, -- Number of unused bytes on overflow pages
+ gap_cnt int -- Number of gaps in the page layout
);}
mem eval $tabledef
proc integerify {real} {
- return [expr int($real)]
+ if {[string is double -strict $real]} {
+ return [expr {int($real)}]
+ } else {
+ return 0
+ }
}
mem function int integerify
@@ -105,7 +114,8 @@ proc cursor_info {arrayvar csr {up 0}} {
a(payload_bytes) \
a(header_bytes) \
a(local_payload_bytes) \
- a(parent) ] [btree_cursor_info $csr $up] {}
+ a(parent) \
+ a(first_ovfl) ] [btree_cursor_info $csr $up] break
}
# Determine the page-size of the database. This global variable is used
@@ -119,7 +129,8 @@ set pageSize [db eval {PRAGMA page_size}]
# database, including the sqlite_master table.
#
set sql {
- SELECT name, rootpage FROM sqlite_master WHERE type='table'
+ SELECT name, rootpage FROM sqlite_master
+ WHERE type='table' AND rootpage>0
UNION ALL
SELECT 'sqlite_master', 1
ORDER BY 1
@@ -144,6 +155,8 @@ foreach {name rootpage} [db eval $sql] {
set ovfl_pages $wideZero ;# Number of overflow pages used
set leaf_pages $wideZero ;# Number of leaf pages
set int_pages $wideZero ;# Number of interior pages
+ set gap_cnt 0 ;# Number of holes in the page sequence
+ set prev_pgno 0 ;# Last page number seen
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -179,6 +192,9 @@ foreach {name rootpage} [db eval $sql] {
set n [expr {int(ceil($ovfl/($pageSize-4.0)))}]
incr ovfl_pages $n
incr unused_ovfl [expr {$n*($pageSize-4) - $ovfl}]
+ set pglist [btree_ovfl_info $DB $csr]
+ } else {
+ set pglist {}
}
# If this is the first table entry analyzed for the page, then update
@@ -190,6 +206,7 @@ foreach {name rootpage} [db eval $sql] {
set seen($ci(page_no)) 1
incr leaf_pages
incr unused_leaf $ci(page_freebytes)
+ set pglist "$ci(page_no) $pglist"
# Now check if the page has a parent that has not been analyzed. If
# so, update the $int_pages, $cnt_int_entry and $unused_int statistics
@@ -209,7 +226,19 @@ foreach {name rootpage} [db eval $sql] {
incr int_pages
incr cnt_int_entry $ci(page_entries)
incr unused_int $ci(page_freebytes)
+
+ # parent pages come before their first child
+ set pglist "$ci(page_no) $pglist"
+ }
+ }
+
+ # Check the page list for fragmentation
+ #
+ foreach pg $pglist {
+ if {$pg!=$prev_pgno+1 && $prev_pgno>0} {
+ incr gap_cnt
}
+ set prev_pgno $pg
}
}
btree_close_cursor $csr
@@ -249,6 +278,7 @@ foreach {name rootpage} [db eval $sql] {
append sql ",$unused_int"
append sql ",$unused_leaf"
append sql ",$unused_ovfl"
+ append sql ",$gap_cnt"
append sql );
mem eval $sql
}
@@ -278,6 +308,8 @@ foreach {name tbl_name rootpage} [db eval $sql] {
set mx_payload $wideZero ;# Maximum payload size
set ovfl_pages $wideZero ;# Number of overflow pages used
set leaf_pages $wideZero ;# Number of leaf pages
+ set gap_cnt 0 ;# Number of holes in the page sequence
+ set prev_pgno 0 ;# Last page number seen
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -323,6 +355,11 @@ foreach {name tbl_name rootpage} [db eval $sql] {
set seen($ci(page_no)) 1
incr leaf_pages
incr unused_leaf $ci(page_freebytes)
+ set pg $ci(page_no)
+ if {$prev_pgno>0 && $pg!=$prev_pgno+1} {
+ incr gap_cnt
+ }
+ set prev_pgno $ci(page_no)
}
}
btree_close_cursor $csr
@@ -354,6 +391,7 @@ foreach {name tbl_name rootpage} [db eval $sql] {
append sql ",0"
append sql ",$unused_leaf"
append sql ",$unused_ovfl"
+ append sql ",$gap_cnt"
append sql );
mem eval $sql
}
@@ -419,7 +457,8 @@ proc subreport {title where} {
int(sum(ovfl_pages)) AS ovfl_pages,
int(sum(leaf_unused)) AS leaf_unused,
int(sum(int_unused)) AS int_unused,
- int(sum(ovfl_unused)) AS ovfl_unused
+ int(sum(ovfl_unused)) AS ovfl_unused,
+ int(sum(gap_cnt)) AS gap_cnt
FROM space_used WHERE $where" {} {}
# Output the sub-report title, nicely decorated with * characters.
@@ -475,6 +514,10 @@ proc subreport {title where} {
if {[info exists avg_fanout]} {
statline {Average fanout} $avg_fanout
}
+ if {$total_pages>1} {
+ set fragmentation [percent $gap_cnt [expr {$total_pages-1}] {fragmentation}]
+ statline {Fragmentation} $fragmentation
+ }
statline {Maximum payload per entry} $mx_payload
statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent
if {$int_pages>0} {
@@ -582,7 +625,9 @@ set user_percent [percent $user_payload $file_bytes]
# Output the summary statistics calculated above.
#
puts "/** Disk-Space Utilization Report For $file_to_analyze"
-puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]"
+catch {
+ puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]"
+}
puts ""
statline {Page size in bytes} $pageSize
statline {Pages in the whole file (measured)} $file_pgcnt
@@ -728,6 +773,14 @@ Average unused bytes per entry
category on a per-entry basis. This is the number of unused bytes on
all pages divided by the number of entries.
+Fragmentation
+
+ The percentage of pages in the table or index that are not
+ consecutive in the disk file. Many filesystems are optimized
+ for sequential file access so smaller fragmentation numbers
+ sometimes result in faster queries, especially for larger
+ database files that do not fit in the disk cache.
+
Maximum payload per entry
The largest payload size of any entry.