Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Change the SQLITE_MASTER format to version 2 in preparation for adding views. (CVS 386) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b2a9807fed544e83002366149b9a3637 |
User & Date: | drh 2002-02-21 12:01:27.000 |
Context
2002-02-23
| ||
02:32 | Code to implement CREATE VIEW is in place. A quick smoke test shows that it works, but there are probably still many bugs. (CVS 387) (check-in: 39fed2df11 user: drh tags: trunk) | |
2002-02-21
| ||
12:01 | Change the SQLITE_MASTER format to version 2 in preparation for adding views. (CVS 386) (check-in: b2a9807fed user: drh tags: trunk) | |
02:25 | Do not allow dot-commands to occur in the middle of a real SQL command. (CVS 385) (check-in: ffb00bf36a user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** ** $Id: build.c,v 1.78 2002/02/21 12:01:27 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement |
︙ | ︙ | |||
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; pTable->isTemp = isTemp; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ sqliteBeginWriteOperation(pParse); if( !isTemp ){ sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1); sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); } } } /* ** Add a new column to the table currently being constructed. ** | > > > > > > > > > > > > > | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; pTable->isTemp = isTemp; if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; /* Begin generating the code that will insert the table record into ** the SQLITE_MASTER table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause ** indices to be created and the table record must come before the ** indices. Hence, the record number for the table must be allocated ** now. */ if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ sqliteBeginWriteOperation(pParse); if( !isTemp ){ sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1); sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); } } } /* ** Add a new column to the table currently being constructed. ** |
︙ | ︙ | |||
653 654 655 656 657 658 659 | /* ** Measure the number of characters needed to output the given ** identifier. The number returned includes any quotes used ** but does not include the null terminator. */ static int identLength(const char *z){ int n; | > | | | | > > > > > | | | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | /* ** Measure the number of characters needed to output the given ** identifier. The number returned includes any quotes used ** but does not include the null terminator. */ static int identLength(const char *z){ int n; int needQuote = 0; for(n=0; *z; n++, z++){ if( *z=='\'' ){ n++; needQuote=1; } } return n + needQuote*2; } /* ** Write an identifier onto the end of the given string. Add ** quote characters as needed. */ static void identPut(char *z, int *pIdx, char *zIdent){ int i, j, needQuote; i = *pIdx; for(j=0; zIdent[j]; j++){ if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break; } needQuote = zIdent[j]!=0 || isdigit(zIdent[0]) || sqliteKeywordCode(zIdent, j)!=TK_ID; if( needQuote ) z[i++] = '\''; for(j=0; zIdent[j]; j++){ z[i++] = zIdent[j]; if( zIdent[j]=='\'' ) z[i++] = '\''; } if( needQuote ) z[i++] = '\''; z[i] = 0; *pIdx = i; } /* ** Generate a CREATE TABLE statement appropriate for the given ** table. Memory to hold the text of the statement is obtained |
︙ | ︙ | |||
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | } /* If the table is generated from a SELECT, then construct the ** list of columns and the text of the table. */ if( pSelect ){ Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect); assert( p->aCol==0 ); p->nCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqliteDeleteTable(0, pSelTab); } /* If the initFlag is 1 it means we are reading the SQL off the ** "sqlite_master" table on the disk. So do not write to the disk ** again. Extract the root page number for the table from the ** pParse->newTnum field. (The page number should have been put ** there by the sqliteOpenCb routine.) */ if( pParse->initFlag ){ p->tnum = pParse->newTnum; } /* If not initializing, then create a record for the new table | > | > | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | } /* If the table is generated from a SELECT, then construct the ** list of columns and the text of the table. */ if( pSelect ){ Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect); if( pSelTab==0 ) return; assert( p->aCol==0 ); p->nCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqliteDeleteTable(0, pSelTab); } /* If the initFlag is 1 it means we are reading the SQL off the ** "sqlite_master" table on the disk. So do not write to the disk ** again. Extract the root page number for the table from the ** pParse->newTnum field. (The page number should have been put ** there by the sqliteOpenCb routine.) */ if( pParse->initFlag ){ p->tnum = pParse->newTnum; } /* If not initializing, then create a record for the new table ** in the SQLITE_MASTER table of the database. The record number ** for the new table entry should already be on the stack. ** ** If this is a TEMPORARY table, then just create the table. Do not ** make an entry in SQLITE_MASTER. */ if( !pParse->initFlag ){ int n, addr; Vdbe *v; v = sqliteGetVdbe(pParse); if( v==0 ) return; addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, p->isTemp); sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, P3_POINTER); p->tnum = 0; if( !p->isTemp ){ sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, -1, "table", P3_STATIC); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); sqliteVdbeAddOp(v, OP_Dup, 4, 0); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** ** $Id: main.c,v 1.61 2002/02/21 12:01:27 drh Exp $ */ #include "sqliteInt.h" #include "os.h" /* ** This is the callback routine for the code that initializes the ** database. See sqliteInit() below for additional information. |
︙ | ︙ | |||
47 48 49 50 51 52 53 54 | break; } case 's': { /* Schema cookie */ db->schema_cookie = atoi(argv[3]); db->next_cookie = db->schema_cookie; break; } case 'i': | > | | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | break; } case 's': { /* Schema cookie */ db->schema_cookie = atoi(argv[3]); db->next_cookie = db->schema_cookie; break; } case 'v': case 'i': case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ if( argv[3] && argv[3][0] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because sParse.initFlag is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. */ memset(&sParse, 0, sizeof(sParse)); sParse.db = db; sParse.initFlag = 1; sParse.newTnum = atoi(argv[2]); sqliteRunParser(&sParse, argv[3], 0); }else{ |
︙ | ︙ | |||
145 146 147 148 149 150 151 | ** indexes. The "rootpage" column holds the number of the root page ** for the b-tree for the table or index. Finally, the "sql" column ** contains the complete text of the CREATE TABLE or CREATE INDEX ** statement that originally created the table or index. If an index ** was created to fulfill a PRIMARY KEY or UNIQUE constraint on a table, ** then the "sql" column is NULL. ** | < | | > > | > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > | | | | | | | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 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 | ** indexes. The "rootpage" column holds the number of the root page ** for the b-tree for the table or index. Finally, the "sql" column ** contains the complete text of the CREATE TABLE or CREATE INDEX ** statement that originally created the table or index. If an index ** was created to fulfill a PRIMARY KEY or UNIQUE constraint on a table, ** then the "sql" column is NULL. ** ** In format 1, entries in the sqlite_master table are in a random ** order. Two passes must be made through the table to initialize ** internal data structures. The first pass reads table definitions ** and the second pass read index definitions. Having two passes ** insures that indices appear after their tables. ** ** In format 2, entries appear in chronological order. Only a single ** pass needs to be made through the table since everything will be ** in the write order. VIEWs may only occur in format 2. ** ** The following program invokes its callback on the SQL for each ** table then goes back and invokes the callback on the ** SQL for each index. The callback will invoke the ** parser to build the internal representation of the ** database scheme. */ static VdbeOp initProg[] = { /* Send the file format to the callback routine */ { OP_Open, 0, 2, 0}, { OP_String, 0, 0, "file-format"}, { OP_String, 0, 0, 0}, { OP_String, 0, 0, 0}, { OP_ReadCookie, 0, 1, 0}, { OP_Callback, 4, 0, 0}, /* Send the initial schema cookie to the callback */ { OP_String, 0, 0, "schema_cookie"}, { OP_String, 0, 0, 0}, { OP_String, 0, 0, 0}, { OP_ReadCookie, 0, 0, 0}, { OP_Callback, 4, 0, 0}, /* Check the file format. If the format number is 2 or more, ** then do a single pass through the SQLITE_MASTER table. For ** a format number of less than 2, jump forward to a different ** algorithm that makes two passes through the SQLITE_MASTER table, ** once for tables and a second time for indices. */ { OP_ReadCookie, 0, 1, 0}, { OP_Integer, 2, 0, 0}, { OP_Lt, 0, 23, 0}, /* This is the code for doing a single scan through the SQLITE_MASTER ** table. This code runs for format 2 and greater. */ { OP_Rewind, 0, 21, 0}, { OP_Column, 0, 0, 0}, /* 15 */ { OP_Column, 0, 1, 0}, { OP_Column, 0, 3, 0}, { OP_Column, 0, 4, 0}, { OP_Callback, 4, 0, 0}, { OP_Next, 0, 15, 0}, { OP_Close, 0, 0, 0}, /* 21 */ { OP_Halt, 0, 0, 0}, /* This is the code for doing two passes through SQLITE_MASTER. This ** code runs for file format 1. */ { OP_Rewind, 0, 43, 0}, /* 23 */ { OP_Column, 0, 0, 0}, /* 24 */ { OP_String, 0, 0, "table"}, { OP_Ne, 0, 32, 0}, { OP_Column, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Column, 0, 3, 0}, { OP_Column, 0, 4, 0}, { OP_Callback, 4, 0, 0}, { OP_Next, 0, 24, 0}, /* 32 */ { OP_Rewind, 0, 43, 0}, /* 33 */ { OP_Column, 0, 0, 0}, /* 34 */ { OP_String, 0, 0, "index"}, { OP_Ne, 0, 42, 0}, { OP_Column, 0, 0, 0}, { OP_Column, 0, 1, 0}, { OP_Column, 0, 3, 0}, { OP_Column, 0, 4, 0}, { OP_Callback, 4, 0, 0}, { OP_Next, 0, 34, 0}, /* 42 */ { OP_Close, 0, 0, 0}, /* 43 */ { OP_Halt, 0, 0, 0}, }; /* Create a virtual machine to run the initialization program. Run ** the program. Then delete the virtual machine. */ vdbe = sqliteVdbeCreate(db); if( vdbe==0 ){ sqliteSetString(pzErrMsg, "out of memory", 0); return SQLITE_NOMEM; } sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg); rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, db->pBusyArg, db->xBusyCallback); sqliteVdbeDelete(vdbe); if( rc==SQLITE_OK && db->nTable==0 ){ db->file_format = 2; } if( rc==SQLITE_OK && db->file_format>2 ){ sqliteSetString(pzErrMsg, "unsupported file format", 0); rc = SQLITE_ERROR; } /* The schema for the SQLITE_MASTER table is not stored in the ** database itself. We have to invoke the callback one extra ** time to get it to process the SQLITE_MASTER table defintion. |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.64 2002/02/21 12:01:27 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
756 757 758 759 760 761 762 | seekOp = pExpr->iColumn==FN_Min ? OP_Rewind : OP_Last; pExpr = pExpr->pList->a[0].pExpr; if( pExpr->op!=TK_COLUMN ) return 0; iCol = pExpr->iColumn; pTab = p->pSrc->a[0].pTab; /* If we get to here, it means the query is of the correct form. | | > > > | | > > > | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | seekOp = pExpr->iColumn==FN_Min ? OP_Rewind : OP_Last; pExpr = pExpr->pList->a[0].pExpr; if( pExpr->op!=TK_COLUMN ) return 0; iCol = pExpr->iColumn; pTab = p->pSrc->a[0].pTab; /* If we get to here, it means the query is of the correct form. ** Check to make sure we have an index and make pIdx point to the ** appropriate index. If the min() or max() is on an INTEGER PRIMARY ** key column, no index is necessary so set pIdx to NULL. If no ** usable index is found, return 0. */ if( iCol<0 ){ pIdx = 0; }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nColumn>=1 ); if( pIdx->aiColumn[0]==iCol ) break; } if( pIdx==0 ) return 0; } /* Identify column names if we will be using the callback. This ** step is skipped if the output is going to a table or a memory cell. */ v = sqliteGetVdbe(pParse); if( v==0 ) return 0; if( eDest==SRT_Callback ){ generateColumnNames(pParse, p->pSrc, p->pEList); } /* Generating code to find the min or the max. Basically all we have ** to do is find the first or the last entry in the chosen index. If ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first ** or last entry in the main table. */ if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); pParse->schemaVerified = 1; } openOp = pTab->isTemp ? OP_OpenAux : OP_Open; base = pParse->nTab; |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.89 2002/02/21 12:01:27 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. */ #define MAX_PAGES 100 #define TEMP_PAGES 25 /* ** Integers of known sizes. These typedefs might change for architectures ** where the sizes very. Preprocessor macros are available so that the ** types can be conveniently redefined at compile-type. Like this: ** ** cc '-DUINTPTR_TYPE=long long int' ... */ |
︙ | ︙ | |||
551 552 553 554 555 556 557 558 559 560 561 562 563 564 | void *sqliteRealloc(void*,int); char *sqliteStrDup(const char*); char *sqliteStrNDup(const char*, int); #endif void sqliteSetString(char **, const char *, ...); void sqliteSetNString(char **, ...); void sqliteDequote(char*); int sqliteRunParser(Parse*, const char*, char **); void sqliteExec(Parse*); Expr *sqliteExpr(int, Expr*, Expr*, Token*); void sqliteExprSpan(Expr*,Token*,Token*); Expr *sqliteExprFunction(ExprList*, Token*); void sqliteExprDelete(Expr*); ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*); | > | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | void *sqliteRealloc(void*,int); char *sqliteStrDup(const char*); char *sqliteStrNDup(const char*, int); #endif void sqliteSetString(char **, const char *, ...); void sqliteSetNString(char **, ...); void sqliteDequote(char*); int sqliteKeywordCode(const char*, int); int sqliteRunParser(Parse*, const char*, char **); void sqliteExec(Parse*); Expr *sqliteExpr(int, Expr*, Expr*, Token*); void sqliteExprSpan(Expr*,Token*,Token*); Expr *sqliteExprFunction(ExprList*, Token*); void sqliteExprDelete(Expr*); ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*); |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** 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. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** 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.37 2002/02/21 12:01:27 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include <stdlib.h> /* |
︙ | ︙ | |||
112 113 114 115 116 117 118 | /* ** This function looks up an identifier to determine if it is a ** keyword. If it is a keyword, the token code of that keyword is ** returned. If the input is not a keyword, TK_ID is returned. */ | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /* ** This function looks up an identifier to determine if it is a ** keyword. If it is a keyword, the token code of that keyword is ** returned. If the input is not a keyword, TK_ID is returned. */ int sqliteKeywordCode(const char *z, int n){ int h; Keyword *p; if( aKeywordTable[0].len==0 ){ /* Initialize the keyword hash table */ sqliteOsEnterMutex(); if( aKeywordTable[0].len==0 ){ int i; |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** 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. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** 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.121 2002/02/21 12:01:27 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ int lastRecno; /* Last recno from a Next or NextIdx operation */ Bool recnoIsValid; /* True if lastRecno is valid */ Bool keyAsData; /* The OP_Column command works on key instead of data */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Btree *pBt; /* Separate file holding temporary table */ }; typedef struct Cursor Cursor; /* ** A sorter builds a list of elements to be sorted. Each element of ** the list is an instance of the following structure. | > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ int lastRecno; /* Last recno from a Next or NextIdx operation */ Bool recnoIsValid; /* True if lastRecno is valid */ Bool keyAsData; /* The OP_Column command works on key instead of data */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Btree *pBt; /* Separate file holding temporary table */ }; typedef struct Cursor Cursor; /* ** A sorter builds a list of elements to be sorted. Each element of ** the list is an instance of the following structure. |
︙ | ︙ | |||
863 864 865 866 867 868 869 | static char *zOpName[] = { 0, "Transaction", "Checkpoint", "Commit", "Rollback", "ReadCookie", "SetCookie", "VerifyCookie", "Open", "OpenTemp", "OpenWrite", "OpenAux", "OpenWrAux", "Close", "MoveTo", "NewRecno", "PutIntKey", "PutStrKey", "Distinct", "Found", "NotFound", "IsUnique", "NotExists", "Delete", "Column", | | | | | | | | | | | | | | | | | | | | | | | | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 | static char *zOpName[] = { 0, "Transaction", "Checkpoint", "Commit", "Rollback", "ReadCookie", "SetCookie", "VerifyCookie", "Open", "OpenTemp", "OpenWrite", "OpenAux", "OpenWrAux", "Close", "MoveTo", "NewRecno", "PutIntKey", "PutStrKey", "Distinct", "Found", "NotFound", "IsUnique", "NotExists", "Delete", "Column", "KeyAsData", "Recno", "FullKey", "NullRow", "Last", "Rewind", "Next", "Destroy", "Clear", "CreateIndex", "CreateTable", "IntegrityCk", "IdxPut", "IdxDelete", "IdxRecno", "IdxGT", "IdxGE", "MemLoad", "MemStore", "ListWrite", "ListRewind", "ListRead", "ListReset", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortCallback", "SortReset", "FileOpen", "FileRead", "FileColumn", "AggReset", "AggFocus", "AggIncr", "AggNext", "AggSet", "AggGet", "SetInsert", "SetFound", "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", "Goto", "If", "Halt", "ColumnCount", "ColumnName", "Callback", "NullCallback", "Integer", "String", "Pop", "Dup", "Pull", "Push", "MustBeInt", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "Precision", "Min", "Max", "Like", "Glob", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Strlen", "Substr", "Limit", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | for(j=p->nCursor; j<=i; j++){ memset(&p->aCsr[j], 0, sizeof(Cursor)); } p->nCursor = i+1; } cleanupCursor(&p->aCsr[i]); memset(&p->aCsr[i], 0, sizeof(Cursor)); do{ rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor); switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); busy = 0; | > | 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 | for(j=p->nCursor; j<=i; j++){ memset(&p->aCsr[j], 0, sizeof(Cursor)); } p->nCursor = i+1; } cleanupCursor(&p->aCsr[i]); memset(&p->aCsr[i], 0, sizeof(Cursor)); p->aCsr[i].nullRow = 1; do{ rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor); switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); busy = 0; |
︙ | ︙ | |||
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 | memset(&p->aCsr[j], 0, sizeof(Cursor)); } p->nCursor = i+1; } pCx = &p->aCsr[i]; cleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt); } if( rc==SQLITE_OK ){ if( pOp->p2 ){ int pgno; | > | 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 | memset(&p->aCsr[j], 0, sizeof(Cursor)); } p->nCursor = i+1; } pCx = &p->aCsr[i]; cleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); pCx->nullRow = 1; rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqliteBtreeBeginTrans(pCx->pBt); } if( rc==SQLITE_OK ){ if( pOp->p2 ){ int pgno; |
︙ | ︙ | |||
2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 | pC->lastRecno = aStack[tos].i; pC->recnoIsValid = res==0; }else{ if( Stringify(p, tos) ) goto no_mem; sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); pC->recnoIsValid = 0; } sqlite_search_count++; if( res<0 ){ sqliteBtreeNext(pC->pCursor, &res); pC->recnoIsValid = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } | > | 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 | pC->lastRecno = aStack[tos].i; pC->recnoIsValid = res==0; }else{ if( Stringify(p, tos) ) goto no_mem; sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); pC->recnoIsValid = 0; } pC->nullRow = 0; sqlite_search_count++; if( res<0 ){ sqliteBtreeNext(pC->pCursor, &res); pC->recnoIsValid = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } |
︙ | ︙ | |||
2888 2889 2890 2891 2892 2893 2894 2895 | BtCursor *pCrsr; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res, rx, iKey; assert( aStack[tos].flags & STK_Int ); iKey = intToKey(aStack[tos].i); rx = sqliteBtreeMoveto(pCrsr, (char*)&iKey, sizeof(int), &res); if( rx!=SQLITE_OK || res!=0 ){ | > > > | > | 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 | BtCursor *pCrsr; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res, rx, iKey; assert( aStack[tos].flags & STK_Int ); iKey = intToKey(aStack[tos].i); rx = sqliteBtreeMoveto(pCrsr, (char*)&iKey, sizeof(int), &res); p->aCsr[i].lastRecno = aStack[tos].i; p->aCsr[i].recnoIsValid = res==0; p->aCsr[i].nullRow = 0; if( rx!=SQLITE_OK || res!=0 ){ pc = pOp->p2 - 1; p->aCsr[i].recnoIsValid = 0; } } POPSTACK; break; } /* Opcode: NewRecno P1 * * |
︙ | ︙ | |||
2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 | }while( cnt<1000 && rx==SQLITE_OK && res==0 ); db->priorNewRowid = v; if( rx==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; goto abort_due_to_error; } } } VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].i = v; aStack[p->tos].flags = STK_Int; break; } | > | 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 | }while( cnt<1000 && rx==SQLITE_OK && res==0 ); db->priorNewRowid = v; if( rx==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; goto abort_due_to_error; } } pC->recnoIsValid = 0; } VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].i = v; aStack[p->tos].flags = STK_Int; break; } |
︙ | ︙ | |||
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, zStack[tos], aStack[tos].n); } POPSTACK; POPSTACK; break; } /* Opcode: Delete P1 * * | > | 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 | } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, zStack[tos], aStack[tos].n); p->aCsr[i].recnoIsValid = 0; } POPSTACK; POPSTACK; break; } /* Opcode: Delete P1 * * |
︙ | ︙ | |||
3109 3110 3111 3112 3113 3114 3115 | VERIFY( if( NeedStack(p, tos+1) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ /* Use different access functions depending on whether the information ** is coming from the key or the data of the record. */ pCrsr = pC->pCursor; | > > | | 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 | VERIFY( if( NeedStack(p, tos+1) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ /* Use different access functions depending on whether the information ** is coming from the key or the data of the record. */ pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; }else if( pC->keyAsData ){ sqliteBtreeKeySize(pCrsr, &payloadSize); xRead = sqliteBtreeKey; }else{ sqliteBtreeDataSize(pCrsr, &payloadSize); xRead = sqliteBtreeData; } |
︙ | ︙ | |||
3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 | BtCursor *pCrsr; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; if( p->aCsr[i].recnoIsValid ){ v = p->aCsr[i].lastRecno; }else{ sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v); v = keyToInt(v); } aStack[tos].i = v; aStack[tos].flags = STK_Int; } | > > > | 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 | BtCursor *pCrsr; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; if( p->aCsr[i].recnoIsValid ){ v = p->aCsr[i].lastRecno; }else if( p->aCsr[i].nullRow ){ aStack[tos].flags = STK_Null; break; }else{ sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v); v = keyToInt(v); } aStack[tos].i = v; aStack[tos].flags = STK_Int; } |
︙ | ︙ | |||
3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 | } sqliteBtreeKey(pCrsr, 0, amt, z); zStack[tos] = z; aStack[tos].n = amt; } break; } /* Opcode: Last P1 P2 * ** ** The next use of the Recno or Column or Next instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Last: { int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; sqliteBtreeLast(pCrsr, &res); | > > > > > > > > > > > > > > > > | | 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 | } sqliteBtreeKey(pCrsr, 0, amt, z); zStack[tos] = z; aStack[tos].n = amt; } break; } /* Opcode: NullRow P1 * * ** ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always push ** a NULL onto the stack. */ case OP_NullRow: { int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ p->aCsr[i].nullRow = 1; } break; } /* Opcode: Last P1 P2 * ** ** The next use of the Recno or Column or Next instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Last: { int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; sqliteBtreeLast(pCrsr, &res); p->aCsr[i].nullRow = res; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } } break; } |
︙ | ︙ | |||
3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 | int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; sqliteBtreeFirst(pCrsr, &res); p->aCsr[i].atFirst = res==0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } } break; } | > | 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 | int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; sqliteBtreeFirst(pCrsr, &res); p->aCsr[i].atFirst = res==0; p->aCsr[i].nullRow = res; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } } break; } |
︙ | ︙ | |||
3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 | case OP_Next: { int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; rc = sqliteBtreeNext(pCrsr, &res); if( res==0 ){ pc = pOp->p2 - 1; sqlite_search_count++; } p->aCsr[i].recnoIsValid = 0; } break; | > | 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 | case OP_Next: { int i = pOp->p1; BtCursor *pCrsr; if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int res; rc = sqliteBtreeNext(pCrsr, &res); p->aCsr[i].nullRow = res; if( res==0 ){ pc = pOp->p2 - 1; sqlite_search_count++; } p->aCsr[i].recnoIsValid = 0; } break; |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** 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. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** 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.44 2002/02/21 12:01:28 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
93 94 95 96 97 98 99 | #define OP_IsUnique 21 #define OP_NotExists 22 #define OP_Delete 23 #define OP_Column 24 #define OP_KeyAsData 25 #define OP_Recno 26 #define OP_FullKey 27 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | #define OP_IsUnique 21 #define OP_NotExists 22 #define OP_Delete 23 #define OP_Column 24 #define OP_KeyAsData 25 #define OP_Recno 26 #define OP_FullKey 27 #define OP_NullRow 28 #define OP_Last 29 #define OP_Rewind 30 #define OP_Next 31 #define OP_Destroy 32 #define OP_Clear 33 #define OP_CreateIndex 34 #define OP_CreateTable 35 #define OP_IntegrityCk 36 #define OP_IdxPut 37 #define OP_IdxDelete 38 #define OP_IdxRecno 39 #define OP_IdxGT 40 #define OP_IdxGE 41 #define OP_MemLoad 42 #define OP_MemStore 43 #define OP_ListWrite 44 #define OP_ListRewind 45 #define OP_ListRead 46 #define OP_ListReset 47 #define OP_SortPut 48 #define OP_SortMakeRec 49 #define OP_SortMakeKey 50 #define OP_Sort 51 #define OP_SortNext 52 #define OP_SortCallback 53 #define OP_SortReset 54 #define OP_FileOpen 55 #define OP_FileRead 56 #define OP_FileColumn 57 #define OP_AggReset 58 #define OP_AggFocus 59 #define OP_AggIncr 60 #define OP_AggNext 61 #define OP_AggSet 62 #define OP_AggGet 63 #define OP_SetInsert 64 #define OP_SetFound 65 #define OP_SetNotFound 66 #define OP_MakeRecord 67 #define OP_MakeKey 68 #define OP_MakeIdxKey 69 #define OP_IncrKey 70 #define OP_Goto 71 #define OP_If 72 #define OP_Halt 73 #define OP_ColumnCount 74 #define OP_ColumnName 75 #define OP_Callback 76 #define OP_NullCallback 77 #define OP_Integer 78 #define OP_String 79 #define OP_Pop 80 #define OP_Dup 81 #define OP_Pull 82 #define OP_Push 83 #define OP_MustBeInt 84 #define OP_Add 85 #define OP_AddImm 86 #define OP_Subtract 87 #define OP_Multiply 88 #define OP_Divide 89 #define OP_Remainder 90 #define OP_BitAnd 91 #define OP_BitOr 92 #define OP_BitNot 93 #define OP_ShiftLeft 94 #define OP_ShiftRight 95 #define OP_AbsValue 96 #define OP_Precision 97 #define OP_Min 98 #define OP_Max 99 #define OP_Like 100 #define OP_Glob 101 #define OP_Eq 102 #define OP_Ne 103 #define OP_Lt 104 #define OP_Le 105 #define OP_Gt 106 #define OP_Ge 107 #define OP_IsNull 108 #define OP_NotNull 109 #define OP_Negative 110 #define OP_And 111 #define OP_Or 112 #define OP_Not 113 #define OP_Concat 114 #define OP_Noop 115 #define OP_Strlen 116 #define OP_Substr 117 #define OP_Limit 118 #define OP_MAX 118 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(sqlite*); void sqliteVdbeCreateCallback(Vdbe*, int*); |
︙ | ︙ |
Changes to test/table.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # # $Id: table.test,v 1.15 2002/02/21 12:01:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic table and verify it is added to sqlite_master # do_test table-1.1 { |
︙ | ︙ | |||
278 279 280 281 282 283 284 | # do_test table-7.1 { set v [catch {execsql { CREATE TABLE weird( desc text, asc text, explain int, | | | | | > > > > > > > > > > > > > | | > > > > > | | > > > | > > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | # do_test table-7.1 { set v [catch {execsql { CREATE TABLE weird( desc text, asc text, explain int, [14_vac] boolean, fuzzy_dog_12 varchar(10), begin blob, end clob ) }} msg] lappend v $msg } {0 {}} do_test table-7.2 { execsql { INSERT INTO weird VALUES('a','b',9,0,'xyz','hi','y''all'); SELECT * FROM weird; } } {a b 9 0 xyz hi y'all} do_test table-7.3 { execsql2 { SELECT * FROM weird; } } {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all} # Try out the CREATE TABLE AS syntax # do_test table-8.1 { execsql2 { CREATE TABLE t2 AS SELECT * FROM weird; SELECT * FROM t2; } } {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all} do_test table-8.1.1 { execsql { SELECT sql FROM sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2( 'desc', 'asc', 'explain', '14_vac', fuzzy_dog_12, 'begin', 'end' )}} do_test table-8.2 { execsql { CREATE TABLE 't3''xyz'(a,b,c); INSERT INTO [t3'xyz] VALUES(1,2,3); SELECT * FROM [t3'xyz]; } } {1 2 3} do_test table-8.3 { execsql2 { CREATE TABLE [t4'abc] AS SELECT count(*) as cnt, max(b+c) FROM [t3'xyz]; SELECT * FROM [t4'abc]; } } {cnt 1 max(b+c) 5} do_test table-8.3.1 { execsql { SELECT sql FROM sqlite_master WHERE name='t4''abc' } } {{CREATE TABLE 't4''abc'(cnt,'max(b+c)')}} do_test table-8.4 { execsql2 { CREATE TEMPORARY TABLE t5 AS SELECT count(*) AS [y'all] FROM [t3'xyz]; SELECT * FROM t5; } } {y'all 1} do_test table-8.5 { db close sqlite db test.db execsql2 { SELECT * FROM [t4'abc]; } } {cnt 1 max(b+c) 5} do_test table-8.6 { execsql2 { SELECT * FROM t2; } } {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all} do_test table-8.7 { catchsql { SELECT * FROM t5; } } {1 {no such table: t5}} do_test table-8.8 { catchsql { CREATE TABLE t5 AS SELECT * FROM no_such_table; } } {1 {no such table: no_such_table}} finish_test |
Changes to www/changes.tcl.
︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | chng {2002 Feb * (2.3.4)} { <li>Change the name of the sanity_check PRAGMA to <b>integrity_check</b> and make it available in all compiles.</li> <li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY clause is handled as a special case which avoids a complete table scan.</li> <li>Automatically generated ROWIDs are now sequential.</li> } chng {2002 Feb 18 (2.3.3)} { <li>Allow identifiers to be quoted in square brackets, for compatibility with MS-Access.</li> <li>Added support for sub-queries in the FROM clause of a SELECT.</li> <li>More efficient implementation of sqliteFileExists() under Windows. | > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | chng {2002 Feb * (2.3.4)} { <li>Change the name of the sanity_check PRAGMA to <b>integrity_check</b> and make it available in all compiles.</li> <li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY clause is handled as a special case which avoids a complete table scan.</li> <li>Automatically generated ROWIDs are now sequential.</li> <li>Do not allow dot-commands of the command-line shell to occur in the middle of a real SQL command.</li> } chng {2002 Feb 18 (2.3.3)} { <li>Allow identifiers to be quoted in square brackets, for compatibility with MS-Access.</li> <li>Added support for sub-queries in the FROM clause of a SELECT.</li> <li>More efficient implementation of sqliteFileExists() under Windows. |
︙ | ︙ |