Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | :-) (CVS 101) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6ed35a1d477906dc7e35bea057995148 |
User & Date: | drh 2000-06-17 13:12:39.000 |
Context
2000-06-19
| ||
19:09 | :-) (CVS 102) (check-in: 8cce4d279d user: drh tags: trunk) | |
2000-06-17
| ||
13:12 | :-) (CVS 101) (check-in: 6ed35a1d47 user: drh tags: trunk) | |
2000-06-16
| ||
20:51 | :-) (CVS 100) (check-in: 1d4fe5599e user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** when syntax rules are reduced. The routines in this file handle | | | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** when syntax rules are reduced. The routines in this file handle ** the following kinds of syntax: ** ** CREATE TABLE ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating expressions and ID lists ** COPY ** VACUUM ** ** $Id: build.c,v 1.18 2000/06/17 13:12:39 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement ** that statement. Prior action routines should have already ** constructed VDBE code to do the work of the SQL statement. ** This routine just has to execute the VDBE code. ** ** Note that if an error occurred, it might be the case that ** no VDBE code was generated. */ void sqliteExec(Parse *pParse){ |
︙ | ︙ | |||
128 129 130 131 132 133 134 | if( sqliteStrICmp(pTable->zName, zName)==0 ) return pTable; } return 0; } /* ** Locate the in-memory structure that describes the | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | if( sqliteStrICmp(pTable->zName, zName)==0 ) return pTable; } return 0; } /* ** Locate the in-memory structure that describes the ** format of a particular index given the name ** of that index. Return NULL if not found. */ Index *sqliteFindIndex(sqlite *db, char *zName){ Index *p; int h; h = sqliteHashNoCase(zName, 0) % N_HASH; for(p=db->apIdxHash[h]; p; p=p->pHash){ |
︙ | ︙ | |||
193 194 195 196 197 198 199 | } sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteFree(pTable); } /* | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | } sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteFree(pTable); } /* ** Construct the name of a user table or index from a token. ** ** Space to hold the name is obtained from sqliteMalloc() and must ** be freed by the calling function. */ char *sqliteTableNameFromToken(Token *pName){ char *zName = sqliteStrNDup(pName->z, pName->n); sqliteDequote(zName); |
︙ | ︙ | |||
291 292 293 294 295 296 297 | /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. ** ** The table structure is added to the internal hash tables. ** | | | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. ** ** The table structure is added to the internal hash tables. ** ** An entry for the table is made in the master table on disk, ** unless initFlag==1. When initFlag==1, it means we are reading ** the master table because we just connected to the database, so ** the entry for this table already exists in the master table. ** We do not want to create it again. */ void sqliteEndTable(Parse *pParse, Token *pEnd){ Table *p; int h; |
︙ | ︙ | |||
373 374 375 376 377 378 379 | if( pTable->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName, " may not be dropped", 0); pParse->nErr++; return; } | | > > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | if( pTable->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName, " may not be dropped", 0); pParse->nErr++; return; } /* Generate code to remove the table from the master table ** on disk. */ v = sqliteGetVdbe(pParse); if( v ){ static VdbeOp dropTable[] = { { OP_Open, 0, 1, MASTER_NAME }, { OP_ListOpen, 0, 0, 0}, { OP_String, 0, 0, 0}, /* 2 */ { OP_Next, 0, ADDR(10), 0}, /* 3 */ |
︙ | ︙ | |||
403 404 405 406 407 408 409 | sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); sqliteVdbeChangeP3(v, base+14, pTable->zName, 0); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0); } } | | | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); sqliteVdbeChangeP3(v, base+14, pTable->zName, 0); for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0); } } /* Remove the in-memory table structure and free its memory. ** ** Exception: if the SQL statement began with the EXPLAIN keyword, ** then no changes are made. */ if( !pParse->explain ){ h = sqliteHashNoCase(pTable->zName, 0) % N_HASH; if( pParse->db->apTblHash[h]==pTable ){ |
︙ | ︙ | |||
429 430 431 432 433 434 435 | /* ** Create a new index for an SQL table. pIndex is the name of the index ** and pTable is the name of the table that is to be indexed. Both will ** be NULL for a primary key. In that case, use pParse->pNewTable as the ** table to be indexed. ** | | | | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | /* ** Create a new index for an SQL table. pIndex is the name of the index ** and pTable is the name of the table that is to be indexed. Both will ** be NULL for a primary key. In that case, use pParse->pNewTable as the ** table to be indexed. ** ** pList is a list of columns to be indexed. pList will be NULL if the ** most recently added column of the table is labeled as the primary key. */ void sqliteCreateIndex( Parse *pParse, /* All information about this parse */ Token *pName, /* Name of the index. May be NULL */ Token *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */ IdList *pList, /* A list of columns to be indexed */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ Token *pEnd /* The ")" that closes the CREATE INDEX statement */ ){ Table *pTab; /* Table to be indexed */ Index *pIndex; /* The index to be created */ char *zName = 0; int i, j, h; |
︙ | ︙ | |||
486 487 488 489 490 491 492 | sqliteSetString(&pParse->zErrMsg, "there is already a table named ", zName, 0); pParse->nErr++; goto exit_create_index; } /* If pList==0, it means this routine was called to make a primary | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | sqliteSetString(&pParse->zErrMsg, "there is already a table named ", zName, 0); pParse->nErr++; goto exit_create_index; } /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ nullId.z = pTab->aCol[pTab->nCol-1].zName; nullId.n = strlen(nullId.z); pList = sqliteIdListAppend(0, &nullId); if( pList==0 ) goto exit_create_index; |
︙ | ︙ | |||
512 513 514 515 516 517 518 | } pIndex->aiField = (int*)&pIndex[1]; pIndex->zName = (char*)&pIndex->aiField[pList->nId]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nField = pList->nId; | | | | | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | } pIndex->aiField = (int*)&pIndex[1]; pIndex->zName = (char*)&pIndex->aiField[pList->nId]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nField = pList->nId; /* Scan the names of the columns of the table to be indexed and ** load the column indices into the Index structure. Report an error ** if any column is not found. */ for(i=0; i<pList->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pList->a[i].zName, 0); pParse->nErr++; sqliteFree(pIndex); goto exit_create_index; } pIndex->aiField[i] = j; } |
︙ | ︙ |
Changes to src/dbbe.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* | | | | > > > > > | | > > > > | > > > | > | > | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains code to implement the database backend (DBBE) ** for sqlite. The database backend is the interface between ** 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.14 2000/06/17 13:12:39 drh Exp $ */ #include "sqliteInt.h" #include <gdbm.h> #include <sys/stat.h> #include <unistd.h> #include <ctype.h> #include <time.h> /* ** Information about each open disk file is an instance of this ** structure. There will only be one such structure for each ** disk file. If the VDBE opens the same file twice (as will happen ** for a self-join, for example) then two DbbeTable structures are ** created but there is only a single BeFile structure with an ** nRef of 2. */ 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 */ int writeable; /* Opened for writing */ BeFile *pNext, *pPrev; /* Next and previous on list of open files */ }; /* ** The following structure holds the current state of the RC4 algorithm. ** We use RC4 as a random number generator. Each call to RC4 gives ** a random 8-bit number. ** ** Nothing in this file or anywhere else in SQLite does any kind of ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** number generator) not as an encryption device. */ 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 */ char **azTemp; /* Names of the temporary files */ struct rc4 rc4; /* The random number generator */ }; /* ** An cursor into a database file is an instance of the following structure. ** There can only be a single BeFile structure for each disk file, but ** there can be multiple DbbeTable structures. Each DbbeTable represents ** a cursor pointing to a particular part of the open BeFile. The ** BeFile.nRef field hold a count of the number of DbbeTable structures ** associated with the same disk file. */ 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 PRNG. "seed" is a pointer to some random ** data used to initialize the PRNG. */ static void rc4init(struct rc4 *p, char *seed, int seedlen){ int i; char k[256]; p->j = 0; p->i = 0; for(i=0; i<256; i++){ p->s[i] = i; k[i] = seed[i%seedlen]; } 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 PRNG. */ 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]; |
︙ | ︙ | |||
229 230 231 232 233 234 235 | zFile[i] = '+'; } } return zFile; } /* | | > > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | zFile[i] = '+'; } } return zFile; } /* ** Generate a random filename with the given prefix. The new filename ** is written into zBuf[]. The calling function must insure that ** zBuf[] is big enough to hold the prefix plus 20 or so extra ** characters. ** ** Very random names are chosen so that the chance of a ** collision with an existing filename is very very small. */ static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){ int i, j; static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789"; |
︙ | ︙ |
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ** 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.5 2000/06/17 13:12:39 drh Exp $ */ #ifndef _SQLITE_DBBE_H_ #define _SQLITE_DBBE_H_ #include <stdio.h> /* ** The database backend supports two opaque structures. A Dbbe is ** a context for the entire set of tables forming a complete ** database. A DbbeTable is a single table. ** ** Note that at this level, the term "table" can mean either an ** SQL table or an SQL index. In this module, a table stores a ** single arbitrary-length key and corresponding arbitrary-length ** data. The differences between tables and indices, and the ** segregation of data into various fields or columns is handled ** by software at higher layers. ** ** The DbbeTable structure holds some state information, such as ** the key and data from the last retrieval. For this reason, ** the backend must allow the creation of multiple independent ** DbbeTable structures for each table in the database. */ typedef struct Dbbe Dbbe; |
︙ | ︙ | |||
87 88 89 90 91 92 93 | /* 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); | | > > > | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /* 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); /* Retrieve the key or data. The result is ephemeral. In other words, ** the result is stored in a buffer that might be overwritten on the next ** call to any DBBE routine. If the results are needed for longer than ** that, you must make a copy. */ char *sqliteDbbeReadKey(DbbeTable*, int offset); char *sqliteDbbeReadData(DbbeTable*, int offset); /* Return the length of the most recently fetched key or data. */ int sqliteDbbeKeyLength(DbbeTable*); int sqliteDbbeDataLength(DbbeTable*); |
︙ | ︙ |
Changes to src/delete.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 DELETE FROM 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 49 50 51 52 53 54 55 56 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.5 2000/06/17 13:12:39 drh Exp $ */ #include "sqliteInt.h" /* ** Process a DELETE FROM statement. */ void sqliteDeleteFrom( Parse *pParse, /* The parser context */ Token *pTableName, /* The table from which we should delete things */ Expr *pWhere /* The WHERE clause. May be null */ ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ IdList *pTabList; /* An ID list holding pTab and nothing else */ int end, addr; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int base; /* Index of the first available table cursor */ /* Locate the table which we want to delete. This table has to be ** put in an IdList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an IdList* parameter instead of just a Table* parameger. */ pTabList = sqliteIdListAppend(0, pTableName); for(i=0; i<pTabList->nId; i++){ pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); if( pTabList->a[i].pTab==0 ){ |
︙ | ︙ | |||
87 88 89 90 91 92 93 | /* Begin the database scan */ sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0); pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1); if( pWInfo==0 ) goto delete_from_cleanup; | | | > > | 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 | /* Begin the database scan */ sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0); pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1); if( pWInfo==0 ) goto delete_from_cleanup; /* Remember the key of every item to be deleted. */ sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0); /* End the database scan loop. */ sqliteWhereEnd(pWInfo); /* Delete every item whose key was written to the list during the ** database scan. We have to delete items after the scan is complete ** because deleting an item can change the scan order. */ base = pParse->nTab; sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0); for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0); } |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* | | > | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions. ** ** $Id: expr.c,v 1.17 2000/06/17 13:12:40 drh Exp $ */ #include "sqliteInt.h" /* ** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables. */ |
︙ | ︙ | |||
55 56 57 58 59 60 61 | /* ** Walk the expression tree and process operators of the form: ** ** expr IN (SELECT ...) ** ** These operators have to be processed before field names are ** resolved because each such operator increments pParse->nTab | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /* ** Walk the expression tree and process operators of the form: ** ** expr IN (SELECT ...) ** ** These operators have to be processed before field names are ** resolved because each such operator increments pParse->nTab ** to reserve cursor numbers for its own use. But pParse->nTab ** needs to be constant once we begin resolving field names. ** ** Actually, the processing of IN-SELECT is only started by this ** routine. This routine allocates a cursor number to the IN-SELECT ** and then moves on. The code generation is done by ** sqliteExprResolveIds() which must be called afterwards. */ |
︙ | ︙ | |||
435 436 437 438 439 440 441 | } } return nErr; } /* ** Generate code into the current Vdbe to evaluate the given | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | } } return nErr; } /* ** Generate code into the current Vdbe to evaluate the given ** expression and leave the result on the top of stack. */ void sqliteExprCode(Parse *pParse, Expr *pExpr){ Vdbe *v = pParse->pVdbe; int op; switch( pExpr->op ){ case TK_PLUS: op = OP_Add; break; case TK_MINUS: op = OP_Subtract; break; |
︙ | ︙ | |||
538 539 540 541 542 543 544 | Token *p = &pExpr->pLeft->token; char *z = sqliteMalloc( p->n + 2 ); sprintf(z, "-%.*s", p->n, p->z); sqliteVdbeAddOp(v, OP_String, 0, 0, z, 0); sqliteFree(z); break; } | | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | Token *p = &pExpr->pLeft->token; char *z = sqliteMalloc( p->n + 2 ); sprintf(z, "-%.*s", p->n, p->z); sqliteVdbeAddOp(v, OP_String, 0, 0, z, 0); sqliteFree(z); break; } /* Fall through into TK_NOT */ } case TK_NOT: { sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, op, 0, 0, 0, 0); break; } case TK_ISNULL: |
︙ | ︙ |
Changes to src/insert.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 INSERT 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 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 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements. ** ** $Id: insert.c,v 1.10 2000/06/17 13:12:40 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) ** insert into TABLE (IDLIST) select ** ** The IDLIST following the table name is always optional. If omitted, ** then a list of all columns for the table is substituted. The IDLIST ** appears in the pField parameter. pField is NULL if IDLIST is omitted. ** ** The pList parameter holds EXPRLIST in the first form of the INSERT ** statement above, and pSelect is NULL. For the second form, pList is ** NULL and pSelect is a pointer to the select statement used to generate ** data for the insert. */ void sqliteInsert( Parse *pParse, /* Parser context */ Token *pTableName, /* Name of table into which we are inserting */ ExprList *pList, /* List of values to be inserted */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pField /* Field names corresponding to IDLIST. */ ){ Table *pTab; /* The table to insert into */ char *zTab; /* Name of the table into which we are inserting */ int i, j, idx; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ int srcTab; /* Date comes from this temporary cursor if >=0 */ int nField; /* Number of columns in the data */ int base; /* First available cursor */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */ /* Locate the table into which we will be inserting new information. */ zTab = sqliteTableNameFromToken(pTableName); pTab = sqliteFindTable(pParse->db, zTab); sqliteFree(zTab); if( pTab==0 ){ sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, pTableName->z, pTableName->n, 0); pParse->nErr++; goto insert_cleanup; } if( pTab->readOnly ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " may not be modified", 0); pParse->nErr++; goto insert_cleanup; } /* Allocate a VDBE */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; /* Figure out how many columns of data are supplied. If the data ** is comming from a SELECT statement, then this step has to generate ** all the code to implement the SELECT statement and leave the data ** in a temporary table. If data is coming from an expression list, ** then we just have to count the number of expressions. */ if( pSelect ){ int rc; srcTab = pParse->nTab++; sqliteVdbeAddOp(v, OP_Open, srcTab, 1, 0, 0); rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); if( rc ) goto insert_cleanup; assert( pSelect->pEList ); nField = pSelect->pEList->nExpr; }else{ srcTab = -1; assert( pList ); nField = pList->nExpr; } /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ if( pField==0 && nField!=pTab->nCol ){ char zNum1[30]; char zNum2[30]; sprintf(zNum1,"%d", nField); sprintf(zNum2,"%d", pTab->nCol); sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has ", zNum2, " columns but ", |
︙ | ︙ | |||
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 | sprintf(zNum1,"%d", nField); sprintf(zNum2,"%d", pField->nId); sqliteSetString(&pParse->zErrMsg, zNum1, " values for ", zNum2, " columns", 0); pParse->nErr++; goto insert_cleanup; } if( pField ){ for(i=0; i<pField->nId; i++){ pField->a[i].idx = -1; } for(i=0; i<pField->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pField->a[i].zName, pTab->aCol[j].zName)==0 ){ pField->a[i].idx = j; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pField->a[i].zName, 0); pParse->nErr++; goto insert_cleanup; } } } base = pParse->nTab; sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Open, idx+base, 1, pIdx->zName, 0); } if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0, 0, 0); iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak, 0, 0); } sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } for(i=0; i<pTab->nCol; i++){ if( pField==0 ){ j = i; | > > > > > > > > > > > > > > > > > > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | sprintf(zNum1,"%d", nField); sprintf(zNum2,"%d", pField->nId); sqliteSetString(&pParse->zErrMsg, zNum1, " values for ", zNum2, " columns", 0); pParse->nErr++; goto insert_cleanup; } /* If the INSERT statement included an IDLIST term, then make sure ** all elements of the IDLIST really are columns of the table and ** remember the column indices. */ if( pField ){ for(i=0; i<pField->nId; i++){ pField->a[i].idx = -1; } for(i=0; i<pField->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqliteStrICmp(pField->a[i].zName, pTab->aCol[j].zName)==0 ){ pField->a[i].idx = j; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has no column named ", pField->a[i].zName, 0); pParse->nErr++; goto insert_cleanup; } } } /* Open cursors into the table that is received the new data and ** all indices of that table. */ base = pParse->nTab; sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqliteVdbeAddOp(v, OP_Open, idx+base, 1, pIdx->zName, 0); } /* If the data source is a SELECT statement, then we have to create ** a loop because there might be multiple rows of data. If the data ** source is an expression list, then exactly one row will be inserted ** and the loop is not used. */ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0, 0, 0); iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak, 0, 0); } /* Create a new entry in the table and fill it with data. */ sqliteVdbeAddOp(v, OP_New, 0, 0, 0, 0); if( pTab->pIndex ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } for(i=0; i<pTab->nCol; i++){ if( pField==0 ){ j = i; |
︙ | ︙ | |||
155 156 157 158 159 160 161 | sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0); | | > > > | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, base, 0, 0, 0); /* Create appropriate entries for the new data row in all indices ** of the table. */ for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ if( pIdx->pNext ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } for(i=0; i<pIdx->nField; i++){ int idx = pIdx->aiField[i]; if( pField==0 ){ |
︙ | ︙ | |||
184 185 186 187 188 189 190 | sqliteVdbeAddOp(v, OP_Field, srcTab, idx, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0); | < > > > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | sqliteVdbeAddOp(v, OP_Field, srcTab, idx, 0, 0); }else{ sqliteExprCode(pParse, pList->a[j].pExpr); } } sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0); } /* The bottom of the loop, if the data source is a SELECT statement */ if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, iBreak); } insert_cleanup: if( pList ) sqliteExprListDelete(pList); if( pSelect ) sqliteSelectDelete(pSelect); sqliteIdListDelete(pField); } |
Changes to src/update.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 UPDATE statements. ** | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.6 2000/06/17 13:12:40 drh Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. */ void sqliteUpdate( |
︙ | ︙ | |||
48 49 50 51 52 53 54 | int base; /* Index of first available table cursor */ Index **apIdx = 0; /* An array of indices that need updating too */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th field of the table. ** aXRef[i]==-1 if the i-th field is not changed. */ /* Locate the table which we want to update. This table has to be | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | int base; /* Index of first available table cursor */ Index **apIdx = 0; /* An array of indices that need updating too */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th field of the table. ** aXRef[i]==-1 if the i-th field is not changed. */ /* Locate the table which we want to update. This table has to be ** put in an IdList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an IdList* parameter instead of just a Table* parameger. */ pTabList = sqliteIdListAppend(0, pTableName); for(i=0; i<pTabList->nId; i++){ pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); if( pTabList->a[i].pTab==0 ){ |
︙ | ︙ | |||
100 101 102 103 104 105 106 | goto update_cleanup; } if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( strcmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ | < | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | goto update_cleanup; } if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( strcmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ aXRef[j] = i; break; } } if( j>=pTab->nCol ){ sqliteSetString(&pParse->zErrMsg, "no such field: ", pChanges->a[i].zName, 0); |
︙ | ︙ | |||
163 164 165 166 167 168 169 | sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0); for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0); } /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some fields | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0); for(i=0; i<nIdx; i++){ sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0); } /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some fields ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entires. */ end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0); |
︙ | ︙ |
Changes to test/index.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # # $Id: index.test,v 1.5 2000/06/17 13:12:40 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic index and verify it is added to sqlite_master # do_test index-1.1 { |
︙ | ︙ | |||
61 62 63 64 65 66 67 | # Try adding an index to a table that does not exist # do_test index-2.1 { set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg] lappend v $msg } {1 {no such table: test1}} | | | | | | | 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 | # Try adding an index to a table that does not exist # do_test index-2.1 { set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg] lappend v $msg } {1 {no such table: test1}} # Try adding an index on a column of a table where the table # exists but the column does not. # do_test index-2.1 { execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg] lappend v $msg } {1 {table test1 has no column named f4}} # Try an index with some columns that match and others that do now. # do_test index-2.2 { set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg] execsql {DROP TABLE test1} lappend v $msg } {1 {table test1 has no column named f4}} # Try creating a bunch of indices on the same table # set r {} for {set i 1} {$i<100} {incr i} { lappend r index$i } |
︙ | ︙ |