Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | added DISTINCT on select (CVS 27) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1f0c4ffd98591e506201b6b0e6e60b92 |
User & Date: | drh 2000-05-31 20:00:52.000 |
Context
2000-05-31
| ||
21:06 | :-) (CVS 28) (check-in: 57c5add197 user: drh tags: trunk) | |
20:00 | added DISTINCT on select (CVS 27) (check-in: 1f0c4ffd98 user: drh tags: trunk) | |
18:33 | :-) (CVS 26) (check-in: 0b7d9eb8ad user: drh tags: trunk) | |
Changes
Changes to src/dbbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** ** This file uses GDBM as the database backend. It should be ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** ** This file uses GDBM as the database backend. It should be ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** ** $Id: dbbe.c,v 1.4 2000/05/31 20:00:52 drh Exp $ */ #include "sqliteInt.h" #include <gdbm.h> #include <sys/stat.h> #include <unistd.h> #include <ctype.h> #include <time.h> /* ** Each open database file is an instance of this structure. */ typedef struct BeFile BeFile; struct BeFile { char *zName; /* Name of the file */ GDBM_FILE dbf; /* The file itself */ int nRef; /* Number of references */ int delOnClose; /* Delete when closing */ BeFile *pNext, *pPrev; /* Next and previous on list of open files */ }; /* ** The following are state variables for the RC4 algorithm. We ** use RC4 as a random number generator. Each call to RC4 gives ** a random 8-bit number. */ struct rc4 { int i, j; int s[256]; }; /* ** The complete database is an instance of the following structure. */ struct Dbbe { char *zDir; /* The directory containing the database */ int write; /* True for write permission */ BeFile *pOpen; /* List of open files */ int nTemp; /* Number of temporary files created */ FILE **apTemp; /* Space to hold temporary file pointers */ struct rc4 rc4; /* The random number generator */ }; /* ** Each file within the database is an instance of this ** structure. */ struct DbbeTable { Dbbe *pBe; /* The database of which this record is a part */ BeFile *pFile; /* The database file for this table */ datum key; /* Most recently used key */ datum data; /* Most recent data */ int needRewind; /* Next key should be the first */ int readPending; /* The fetch hasn't actually been done yet */ }; /* ** Initialize the RC4 algorithm. */ static void rc4init(struct rc4 *p, char *key, int keylen){ int i; char k[256]; p->j = 0; p->i = 0; for(i=0; i<256; i++){ p->s[i] = i; k[i] = key[i%keylen]; } for(i=0; i<256; i++){ int t; p->j = (p->j + p->s[i] + k[i]) & 0xff; t = p->s[p->j]; p->s[p->j] = p->s[i]; p->s[i] = t; } } /* ** Get a single 8-bit random value from the RC4 algorithm. */ static int rc4byte(struct rc4 *p){ int t; p->i = (p->i + 1) & 0xff; p->j = (p->j + p->s[p->i]) & 0xff; t = p->s[p->i]; p->s[p->i] = p->s[p->j]; p->s[p->j] = t; t = p->s[p->i] + p->s[p->j]; return t & 0xff; } /* ** This routine opens a new database. For the current driver scheme, ** the database name is the name of the directory ** containing all the files of the database. */ Dbbe *sqliteDbbeOpen( |
︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | sqliteSetString(pzErrMsg, "out of memory", 0); return 0; } pNew->zDir = (char*)&pNew[1]; strcpy(pNew->zDir, zName); pNew->write = write; pNew->pOpen = 0; return pNew; } /* ** Completely shutdown the given database. Close all files. Free all memory. */ void sqliteDbbeClose(Dbbe *pBe){ | > > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | sqliteSetString(pzErrMsg, "out of memory", 0); return 0; } pNew->zDir = (char*)&pNew[1]; strcpy(pNew->zDir, zName); pNew->write = write; pNew->pOpen = 0; time(&statbuf.st_ctime); rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf)); return pNew; } /* ** Completely shutdown the given database. Close all files. Free all memory. */ void sqliteDbbeClose(Dbbe *pBe){ |
︙ | ︙ | |||
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | zFile[i] = tolower(c); }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){ zFile[i] = '+'; } } return zFile; } /* ** Open a new table cursor */ DbbeTable *sqliteDbbeOpenTable( Dbbe *pBe, /* The database the table belongs to */ const char *zTable, /* The name of the table */ int writeable /* True to open for writing */ ){ char *zFile; /* Name of the table file */ DbbeTable *pTable; /* The new table cursor */ BeFile *pFile; /* The underlying data file for this table */ pTable = sqliteMalloc( sizeof(*pTable) ); if( pTable==0 ) return 0; | > > > > > > > > > > > > > > > > > | | | > > > > > | > > > > > > > > > > > > > > > > | 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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | zFile[i] = tolower(c); }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){ zFile[i] = '+'; } } return zFile; } /* ** Generate a random filename with the given prefix. */ static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){ int i, j; static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789"; strcpy(zBuf, zPrefix); j = strlen(zBuf); for(i=0; i<15; i++){ int c = (rc4byte(pRc4) & 0x7f) % (sizeof(zRandomChars) - 1); zBuf[j++] = zRandomChars[c]; } zBuf[j] = 0; } /* ** Open a new table cursor */ DbbeTable *sqliteDbbeOpenTable( Dbbe *pBe, /* The database the table belongs to */ const char *zTable, /* The name of the table */ int writeable /* True to open for writing */ ){ char *zFile; /* Name of the table file */ DbbeTable *pTable; /* The new table cursor */ BeFile *pFile; /* The underlying data file for this table */ pTable = sqliteMalloc( sizeof(*pTable) ); if( pTable==0 ) return 0; if( zTable ){ zFile = sqliteFileOfTable(pBe, zTable); for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ if( strcmp(pFile->zName,zFile)==0 ) break; } }else{ pFile = 0; zFile = 0; } if( pFile==0 ){ pFile = sqliteMalloc( sizeof(*pFile) ); if( pFile==0 ){ sqliteFree(zFile); return 0; } pFile->zName = zFile; pFile->nRef = 1; pFile->pPrev = 0; if( pBe->pOpen ){ pBe->pOpen->pPrev = pFile; } pFile->pNext = pBe->pOpen; pBe->pOpen = pFile; if( pFile->zName ){ pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0); }else{ int i, j, limit; struct rc4 *pRc4; char zRandom[50]; pRc4 = &pBe->rc4; zFile = 0; limit = 5; do { randomName(&pBe->rc4, zRandom, "_temp_table_"); sqliteFree(zFile); zFile = sqliteFileOfTable(pBe, zRandom); pFile->dbf = gdbm_open(zFile, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0); }while( pFile->dbf==0 && limit-- >= 0); pFile->zName = zFile; pFile->delOnClose = 1; } }else{ sqliteFree(zFile); pFile->nRef++; } pTable->pBe = pBe; pTable->pFile = pFile; pTable->readPending = 0; |
︙ | ︙ | |||
235 236 237 238 239 240 241 242 243 244 245 246 247 248 | if( pFile->pPrev ){ pFile->pPrev->pNext = pFile->pNext; }else{ pBe->pOpen = pFile->pNext; } if( pFile->pNext ){ pFile->pNext->pPrev = pFile->pPrev; } sqliteFree(pFile->zName); memset(pFile, 0, sizeof(*pFile)); sqliteFree(pFile); } if( pTable->key.dptr ) free(pTable->key.dptr); if( pTable->data.dptr ) free(pTable->data.dptr); | > > > | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | if( pFile->pPrev ){ pFile->pPrev->pNext = pFile->pNext; }else{ pBe->pOpen = pFile->pNext; } if( pFile->pNext ){ pFile->pNext->pPrev = pFile->pPrev; } if( pFile->delOnClose ){ unlink(pFile->zName); } sqliteFree(pFile->zName); memset(pFile, 0, sizeof(*pFile)); sqliteFree(pFile); } if( pTable->key.dptr ) free(pTable->key.dptr); if( pTable->data.dptr ) free(pTable->data.dptr); |
︙ | ︙ | |||
270 271 272 273 274 275 276 277 278 279 280 281 282 283 | datumClear(&pTable->key); datumClear(&pTable->data); if( pTable->pFile && pTable->pFile->dbf ){ pTable->data = gdbm_fetch(pTable->pFile->dbf, key); } return pTable->data.dptr!=0; } /* ** Copy bytes from the current key or data into a buffer supplied by ** the calling function. Return the number of bytes copied. */ int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){ int n; | > > > > > > > > > > > > > > > | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | datumClear(&pTable->key); datumClear(&pTable->data); if( pTable->pFile && pTable->pFile->dbf ){ pTable->data = gdbm_fetch(pTable->pFile->dbf, key); } return pTable->data.dptr!=0; } /* ** Return 1 if the given key is already in the table. Return 0 ** if it is not. */ int sqliteDbbeTest(DbbeTable *pTable, int nKey, char *pKey){ datum key; int result = 0; key.dsize = nKey; key.dptr = pKey; if( pTable->pFile && pTable->pFile->dbf ){ result = gdbm_exists(pTable->pFile->dbf, key); } return result; } /* ** Copy bytes from the current key or data into a buffer supplied by ** the calling function. Return the number of bytes copied. */ int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){ int n; |
︙ | ︙ | |||
373 374 375 376 377 378 379 380 | pTable->needRewind = 1; pTable->readPending = 0; rc = 0; } return rc; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | > | | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | pTable->needRewind = 1; pTable->readPending = 0; rc = 0; } return rc; } /* ** Get a new integer key. */ int sqliteDbbeNew(DbbeTable *pTable){ int iKey; datum key; int go = 1; int i; struct rc4 *pRc4; if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1; pRc4 = &pTable->pBe->rc4; while( go ){ iKey = 0; for(i=0; i<4; i++){ iKey = (iKey<<8) + rc4byte(pRc4); } key.dptr = (char*)&iKey; key.dsize = 4; go = gdbm_exists(pTable->pFile->dbf, key); } return iKey; } |
︙ | ︙ | |||
484 485 486 487 488 489 490 | } /* ** Open a temporary file. */ FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){ char *zFile; | | | > | > > > | > | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | } /* ** Open a temporary file. */ FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){ char *zFile; char zBuf[50]; int i, j; int limit; for(i=0; i<pBe->nTemp; i++){ if( pBe->apTemp[i]==0 ) break; } if( i>=pBe->nTemp ){ pBe->nTemp++; pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) ); } if( pBe->apTemp==0 ) return 0; limit = 4; zFile = 0; do{ randomName(&pBe->rc4, zBuf, "/_temp_file_"); sqliteFree(zFile); sqliteSetString(&zFile, pBe->zDir, zBuf, 0); }while( access(zFile,0) && limit-- >= 0 ); pBe->apTemp[i] = fopen(zFile, "w+"); sqliteFree(zFile); return pBe->apTemp[i]; } /* ** Close a temporary file opened using sqliteDbbeOpenTempFile() |
︙ | ︙ |
Changes to src/dbbe.h.
︙ | ︙ | |||
24 25 26 27 28 29 30 | ** This file defines the interface to the database backend (Dbbe). ** ** The database backend is designed to be as general as possible ** so that it can easily be replaced by a different backend. ** This library was originally designed to support the following ** backends: GDBM, NDBM, SDBM, Berkeley DB. ** | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** This file defines the interface to the database backend (Dbbe). ** ** The database backend is designed to be as general as possible ** so that it can easily be replaced by a different backend. ** This library was originally designed to support the following ** backends: GDBM, NDBM, SDBM, Berkeley DB. ** ** $Id: dbbe.h,v 1.3 2000/05/31 20:00:52 drh Exp $ */ #ifndef _SQLITE_DBBE_H_ #define _SQLITE_DBBE_H_ #include <stdio.h> /* ** The database backend supports two opaque structures. A Dbbe is |
︙ | ︙ | |||
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 | Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr); /* Close the whole database. */ void sqliteDbbeClose(Dbbe*); /* Open a particular table of a previously opened database. ** Create the table if it doesn't already exist and writeable!=0. */ DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable); /* Delete a table from the database */ void sqliteDbbeDropTable(Dbbe*, const char *zTableName); /* Reorganize a table to speed access or reduce its disk usage */ void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName); /* Close a table */ void sqliteDbbeCloseTable(DbbeTable*); /* Fetch an entry from a table with the given key. Return 1 if ** successful and 0 if no such entry exists. */ int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey); /* Retrieve the key or data used for the last fetch. Only size ** bytes are read beginning with the offset-th byte. The return ** value is the actual number of bytes read. */ int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf); int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf); | > > > > > > > > | 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 | Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr); /* Close the whole database. */ void sqliteDbbeClose(Dbbe*); /* Open a particular table of a previously opened database. ** Create the table if it doesn't already exist and writeable!=0. ** ** If zTableName is 0 or "", then a temporary table is created that ** will be deleted when closed. */ DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable); /* Delete a table from the database */ void sqliteDbbeDropTable(Dbbe*, const char *zTableName); /* Reorganize a table to speed access or reduce its disk usage */ void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName); /* Close a table */ void sqliteDbbeCloseTable(DbbeTable*); /* Fetch an entry from a table with the given key. Return 1 if ** successful and 0 if no such entry exists. */ int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey); /* Return 1 if the given key is already in the table. Return 0 ** if it is not. */ int sqliteDbbeTest(DbbeTable*, int nKey, char *pKey); /* Retrieve the key or data used for the last fetch. Only size ** bytes are read beginning with the offset-th byte. The return ** value is the actual number of bytes read. */ int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf); int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf); |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** ************************************************************************* ** 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. ** | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** ************************************************************************* ** 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.6 2000/05/31 20:00:52 drh Exp $ */ %token_prefix TK_ %token_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetNString(&pParse->zErrMsg,"syntax error near \"",0,TOKEN.z,TOKEN.n, "\"", 1, 0); |
︙ | ︙ | |||
121 122 123 124 125 126 127 | // The next command format is dropping tables. // cmd ::= DROP TABLE id(X). {sqliteDropTable(pParse,&X);} // The select statement // cmd ::= select. | | | | | > > > > > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | // The next command format is dropping tables. // cmd ::= DROP TABLE id(X). {sqliteDropTable(pParse,&X);} // The select statement // cmd ::= select. select ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) orderby_opt(Z). {sqliteSelect(pParse, W, X, Y, Z, D);} select ::= SELECT distinct(D) STAR from(X) where_opt(Y) orderby_opt(Z). {sqliteSelect(pParse, 0, X, Y, Z, D);} %type distinct {int} distinct(A) ::= DISTINCT. {A = 1;} distinct(A) ::= . {A = 0;} %type selcollist {ExprList*} %destructor selcollist {sqliteExprListDelete($$);} %type sclp {ExprList*} %destructor sclp {sqliteExprListDelete($$);} sclp(A) ::= selcollist(X) COMMA. {A = X;} |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** | | | > | 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 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** ** $Id: select.c,v 1.3 2000/05/31 20:00:52 drh Exp $ */ #include "sqliteInt.h" /* ** Process a SELECT statement. */ void sqliteSelect( Parse *pParse, /* The parser context */ ExprList *pEList, /* List of fields to extract. NULL means "*" */ IdList *pTabList, /* List of tables to select from */ Expr *pWhere, /* The WHERE clause. May be NULL */ ExprList *pOrderBy, /* The ORDER BY clause. May be NULL */ int distinct /* If true, only output distinct results */ ){ int i, j; WhereInfo *pWInfo; Vdbe *v; int isAgg = 0; /* True for select lists like "count(*)" */ if( pParse->nErr>0 ) goto select_cleanup; |
︙ | ︙ | |||
116 117 118 119 120 121 122 123 124 125 126 127 128 129 | /* ORDER BY is ignored if this is an aggregate query like count(*) ** since only one row will be returned. */ if( isAgg && pOrderBy ){ sqliteExprListDelete(pOrderBy); pOrderBy = 0; } /* Begin generating code. */ v = pParse->pVdbe; if( v==0 ){ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe); } | > > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | /* ORDER BY is ignored if this is an aggregate query like count(*) ** since only one row will be returned. */ if( isAgg && pOrderBy ){ sqliteExprListDelete(pOrderBy); pOrderBy = 0; } /* Turn off distinct if this is an aggregate */ if( isAgg ){ distinct = 0; } /* Begin generating code. */ v = pParse->pVdbe; if( v==0 ){ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe); } |
︙ | ︙ | |||
184 185 186 187 188 189 190 | break; } } } } /* Begin the database scan | | > > > > > > > > > > > > > > > > > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 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 232 | break; } } } } /* Begin the database scan */ if( distinct ){ distinct = pTabList->nId*2+1; sqliteVdbeAddOp(v, OP_Open, distinct, 0, 0, 0); } pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0); if( pWInfo==0 ) goto select_cleanup; /* Pull the requested fields. */ if( !isAgg ){ for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } } /* If the current result is not distinct, script the remainder ** of this processing. */ if( distinct ){ int isDistinct = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1, 0, 0); sqliteVdbeAddOp(v, OP_Distinct, distinct, isDistinct, 0, 0); sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, "", isDistinct); sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0); } /* If there is no ORDER BY clause, then we can invoke the callback ** right away. If there is an ORDER BY, then we need to put the ** data into an appropriate sorter record. */ if( pOrderBy ){ char *zSortOrder; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.6 2000/05/31 20:00:52 drh Exp $ */ #include "sqlite.h" #include "dbbe.h" #include "vdbe.h" #include "parse.h" #include <gdbm.h> #include <stdio.h> |
︙ | ︙ | |||
245 246 247 248 249 250 251 | void sqliteDeleteTable(sqlite*, Table*); void sqliteInsert(Parse*, Token*, ExprList*, IdList*); IdList *sqliteIdListAppend(IdList*, Token*); void sqliteIdListAddAlias(IdList*, Token*); void sqliteIdListDelete(IdList*); void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*); void sqliteDropIndex(Parse*, Token*); | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | void sqliteDeleteTable(sqlite*, Table*); void sqliteInsert(Parse*, Token*, ExprList*, IdList*); IdList *sqliteIdListAppend(IdList*, Token*); void sqliteIdListAddAlias(IdList*, Token*); void sqliteIdListDelete(IdList*); void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*); void sqliteDropIndex(Parse*, Token*); void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*, int); void sqliteDeleteFrom(Parse*, Token*, Expr*); void sqliteUpdate(Parse*, Token*, ExprList*, Expr*); WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int); void sqliteWhereEnd(WhereInfo*); void sqliteExprCode(Parse*, Expr*); void sqliteExprIfTrue(Parse*, Expr*, int); void sqliteExprIfFalse(Parse*, Expr*, int); |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ************************************************************************* ** 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. ** | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ************************************************************************* ** 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.5 2000/05/31 20:00:53 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include <stdlib.h> /* ** All the keywords of the SQL language are stored as in a hash |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | { "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, { "COPY", 0, TK_COPY, 0 }, { "CREATE", 0, TK_CREATE, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 }, { "DELETE", 0, TK_DELETE, 0 }, { "DELIMITERS", 0, TK_DELIMITERS, 0 }, { "DESC", 0, TK_DESC, 0 }, { "DROP", 0, TK_DROP, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "FROM", 0, TK_FROM, 0 }, { "GLOB", 0, TK_GLOB, 0 }, { "INDEX", 0, TK_INDEX, 0 }, { "INSERT", 0, TK_INSERT, 0 }, { "INTO", 0, TK_INTO, 0 }, | > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | { "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, { "COPY", 0, TK_COPY, 0 }, { "CREATE", 0, TK_CREATE, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 }, { "DELETE", 0, TK_DELETE, 0 }, { "DELIMITERS", 0, TK_DELIMITERS, 0 }, { "DESC", 0, TK_DESC, 0 }, { "DISTINCT", 0, TK_DISTINCT, 0 }, { "DROP", 0, TK_DROP, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "FROM", 0, TK_FROM, 0 }, { "GLOB", 0, TK_GLOB, 0 }, { "INDEX", 0, TK_INDEX, 0 }, { "INSERT", 0, TK_INSERT, 0 }, { "INTO", 0, TK_INTO, 0 }, |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | ** inplicit conversion from one type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** inplicit conversion from one type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.5 2000/05/31 20:00:53 drh Exp $ */ #include "sqliteInt.h" /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. |
︙ | ︙ | |||
388 389 390 391 392 393 394 | ** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h ** change, be sure to change this array to match. You can use the ** "opNames.awk" awk script which is part of the source tree to regenerate ** this array, then copy and paste it into this file, if you want. */ static char *zOpName[] = { 0, "Open", "Close", "Fetch", "New", | | | | | | | | | | | | | | | | | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | ** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h ** change, be sure to change this array to match. You can use the ** "opNames.awk" awk script which is part of the source tree to regenerate ** this array, then copy and paste it into this file, if you want. */ static char *zOpName[] = { 0, "Open", "Close", "Fetch", "New", "Put", "Distinct", "Delete", "Field", "Key", "Rewind", "Next", "Destroy", "Reorganize", "ResetIdx", "NextIdx", "PutIdx", "DeleteIdx", "ListOpen", "ListWrite", "ListRewind", "ListRead", "ListClose", "SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortKey", "SortCallback", "SortClose", "FileOpen", "FileRead", "FileField", "FileClose", "MakeRecord", "MakeKey", "Goto", "If", "Halt", "ColumnCount", "ColumnName", "Callback", "Integer", "String", "Pop", "Dup", "Pull", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Min", "Max", "Like", "Glob", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 | NeedStack(p, p->tos+1); p->tos++; p->iStack[p->tos] = nByte; p->zStack[p->tos] = zNewRecord; break; } | | > > > > > | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | NeedStack(p, p->tos+1); p->tos++; p->iStack[p->tos] = nByte; p->zStack[p->tos] = zNewRecord; break; } /* Opcode: MakeKey P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry suitable ** for use as the key in an index or a sort. The top P1 records are ** concatenated with a tab character (ASCII 0x09) used as a record ** separator. The entire concatenation is null-terminated. The ** lowest entry in the stack is the first field and the top of the ** stack becomes the last. ** ** If P2 is not zero, then the original entries remain on the stack ** and the new key is pushed on top. If P2 is zero, the original ** data is popped off the stack first then the new key is pushed ** back in its place. ** ** See also the SortMakeKey opcode. */ case OP_MakeKey: { char *zNewKey; int nByte; int nField; |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 | j = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1); j += p->iStack[i]-1; if( i<p->tos ) zNewKey[j++] = '\t'; } zNewKey[j] = 0; | | | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 | j = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1); j += p->iStack[i]-1; if( i<p->tos ) zNewKey[j++] = '\t'; } zNewKey[j] = 0; if( pOp->p2==0 ) PopStack(p, nField); NeedStack(p, p->tos+1); p->tos++; p->iStack[p->tos] = nByte; p->zStack[p->tos] = zNewKey; break; } |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | }else{ sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]); } } PopStack(p, 1); break; } /* Opcode: New P1 * * ** ** Get a new integer key not previous used by table P1 and ** push it onto the stack. */ case OP_New: { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | }else{ sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]); } } PopStack(p, 1); break; } /* Opcode: Distinct P1 P2 * ** ** Use the top of the stack as a key. If a record with that key ** does not exist in table P1, then jump to P2. If the record ** does already exist, then fall thru. The record is not retrieved. ** The key is not popped from the stack. */ case OP_Distinct: { int i = pOp->p1; int tos = p->tos; int alreadyExists = 0; if( tos<0 ) goto not_enough_stack; if( i>=0 && i<p->nTable && p->aTab[i].pTable ){ if( p->zStack[tos]==0 ){ alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, sizeof(int), (char*)&p->iStack[tos]); }else{ alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]); } } if( !alreadyExists ){ pc = pOp->p2; if( pc<0 || pc>p->nOp ){ sqliteSetString(pzErrMsg, "jump destination out of range", 0); rc = 1; } pc--; } break; } /* Opcode: New P1 * * ** ** Get a new integer key not previous used by table P1 and ** push it onto the stack. */ case OP_New: { |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.4 2000/05/31 20:00:53 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
72 73 74 75 76 77 78 | ** can be used to renumber these opcodes when new opcodes are inserted. */ #define OP_Open 1 #define OP_Close 2 #define OP_Fetch 3 #define OP_New 4 #define OP_Put 5 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | ** can be used to renumber these opcodes when new opcodes are inserted. */ #define OP_Open 1 #define OP_Close 2 #define OP_Fetch 3 #define OP_New 4 #define OP_Put 5 #define OP_Distinct 6 #define OP_Delete 7 #define OP_Field 8 #define OP_Key 9 #define OP_Rewind 10 #define OP_Next 11 #define OP_Destroy 12 #define OP_Reorganize 13 #define OP_ResetIdx 14 #define OP_NextIdx 15 #define OP_PutIdx 16 #define OP_DeleteIdx 17 #define OP_ListOpen 18 #define OP_ListWrite 19 #define OP_ListRewind 20 #define OP_ListRead 21 #define OP_ListClose 22 #define OP_SortOpen 23 #define OP_SortPut 24 #define OP_SortMakeRec 25 #define OP_SortMakeKey 26 #define OP_Sort 27 #define OP_SortNext 28 #define OP_SortKey 29 #define OP_SortCallback 30 #define OP_SortClose 31 #define OP_FileOpen 32 #define OP_FileRead 33 #define OP_FileField 34 #define OP_FileClose 35 #define OP_MakeRecord 36 #define OP_MakeKey 37 #define OP_Goto 38 #define OP_If 39 #define OP_Halt 40 #define OP_ColumnCount 41 #define OP_ColumnName 42 #define OP_Callback 43 #define OP_Integer 44 #define OP_String 45 #define OP_Pop 46 #define OP_Dup 47 #define OP_Pull 48 #define OP_Add 49 #define OP_AddImm 50 #define OP_Subtract 51 #define OP_Multiply 52 #define OP_Divide 53 #define OP_Min 54 #define OP_Max 55 #define OP_Like 56 #define OP_Glob 57 #define OP_Eq 58 #define OP_Ne 59 #define OP_Lt 60 #define OP_Le 61 #define OP_Gt 62 #define OP_Ge 63 #define OP_IsNull 64 #define OP_NotNull 65 #define OP_Negative 66 #define OP_And 67 #define OP_Or 68 #define OP_Not 69 #define OP_Concat 70 #define OP_Noop 71 #define OP_MAX 71 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(Dbbe*); int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int); |
︙ | ︙ |
Changes to www/index.tcl.
1 2 3 | # # Run this TCL script to generate HTML for the index.html file. # | | | 1 2 3 4 5 6 7 8 9 10 11 | # # Run this TCL script to generate HTML for the index.html file. # set rcsid {$Id: index.tcl,v 1.7 2000/05/31 20:00:53 drh Exp $} puts {<html> <head><title>SQLite: An SQL Frontend For GDBM</title></head> <body bgcolor=white> <h1 align=center>SQLite: An SQL Frontend For GDBM</h1> <p align=center>} puts "Last modified [lrange $rcsid 3 4] GMT" |
︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | http://www.gnu.org/software/gdbm/gdbm.html</a></p></li> <li><p>Someday, we would like to port SQLite to work with the Berkeley DB library in addition to GDBM. For information about the Berkeley DB library, see <a href="http://www.sleepcat.com/">http://www.sleepycat.com</a> </p></li> </ul>} puts { <p><hr /></p> <p> <a href="../index.html"><img src="/goback.jpg" border=0 /> More Open Source Software</a> from Hwaci. </p> </body></html>} | > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | http://www.gnu.org/software/gdbm/gdbm.html</a></p></li> <li><p>Someday, we would like to port SQLite to work with the Berkeley DB library in addition to GDBM. For information about the Berkeley DB library, see <a href="http://www.sleepcat.com/">http://www.sleepycat.com</a> </p></li> <li><p>Here is a <a href="http://w3.one.net/~jhoffman/sqltut.htm"> tutorial on SQL</a>.</p></li> </ul>} puts { <p><hr /></p> <p> <a href="../index.html"><img src="/goback.jpg" border=0 /> More Open Source Software</a> from Hwaci. </p> </body></html>} |