Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. ** -** $Id: alter.c,v 1.11 2005/12/09 20:02:05 drh Exp $ +** $Id: alter.c,v 1.12 2005/12/16 01:06:17 drh Exp $ */ #include "sqliteInt.h" #include /* @@ -460,24 +460,31 @@ /* If the default value of the new column is NULL, then set the file ** format to 2. If the default value of the new column is not NULL, ** the file format becomes 3. */ - if( (v=sqlite3GetVdbe(pParse))!=0 ){ - int f = (pDflt?3:2); - - /* Only set the file format to $f if it is currently less than $f. */ - sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); - sqlite3VdbeAddOp(v, OP_Integer, f, 0); - sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp(v, OP_Integer, f, 0); - sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); - } + sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); } + +/* +** Generate code to make sure the file format number is at least minFormat. +** The generated code will increase the file format number if necessary. +*/ +void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ + Vdbe *v; + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); + sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); + sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); + sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); + sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); + } +} /* ** This function is called by the parser after the table-name in ** an "ALTER TABLE ADD" statement is parsed. Argument Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -20,11 +20,11 @@ ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.357 2005/12/09 20:02:05 drh Exp $ +** $Id: build.c,v 1.358 2005/12/16 01:06:17 drh Exp $ */ #include "sqliteInt.h" #include /* @@ -762,11 +762,11 @@ ** set them now. */ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ lbl = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_If, 0, lbl); - sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0); + sqlite3VdbeAddOp(v, OP_Integer, 1, 0); /* file format defaults to 1 */ sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4); sqlite3VdbeResolveLabel(v, lbl); @@ -1008,11 +1008,12 @@ */ void sqlite3AddPrimaryKey( Parse *pParse, /* Parsing context */ ExprList *pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ - int autoInc /* True if the AUTOINCREMENT keyword is present */ + int autoInc, /* True if the AUTOINCREMENT keyword is present */ + int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; if( pTab==0 ) goto primary_key_exit; @@ -1039,21 +1040,22 @@ if( pList->nExpr>1 ) iCol = -1; } if( iCol>=0 && iColnCol ){ zType = pTab->aCol[iCol].zType; } - if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){ + if( zType && sqlite3StrICmp(zType, "INTEGER")==0 + && sortOrder==SQLITE_SO_ASC ){ pTab->iPKey = iCol; pTab->keyConf = onError; pTab->autoInc = autoInc; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ - sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0); + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pList); @@ -2092,22 +2094,28 @@ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ - Token *pEnd /* The ")" that closes the CREATE INDEX statement */ + Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ + int sortOrder /* Sort order of primary key when pList==NULL */ ){ - Table *pTab = 0; /* Table to be indexed */ - Index *pIndex = 0; /* The index to be created */ - char *zName = 0; + Table *pTab = 0; /* Table to be indexed */ + Index *pIndex = 0; /* The index to be created */ + char *zName = 0; /* Name of the index */ + int nName; /* Number of characters in zName */ int i, j; - Token nullId; /* Fake token for an empty ID list */ - DbFixer sFix; /* For assigning database names to pTable */ + Token nullId; /* Fake token for an empty ID list */ + DbFixer sFix; /* For assigning database names to pTable */ + int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ + int descSeen = 0; /* Changes to true if a DESC is seen */ sqlite3 *db = pParse->db; - - int iDb; /* Index of the database that is being written */ - Token *pName = 0; /* Unqualified name of the index to create */ + Db *pDb; /* The specific table containing the indexed database */ + int iDb; /* Index of the database that is being written */ + Token *pName = 0; /* Unqualified name of the index to create */ + struct ExprList_item *pListItem; /* For looping over pList */ + CollSeq *pCollSeq; /* Collating sequence for one index column */ if( pParse->nErr || sqlite3Tsd()->mallocFailed ) goto exit_create_index; /* ** Find the table that is to be indexed. Return early if not found. @@ -2146,10 +2154,11 @@ }else{ assert( pName==0 ); pTab = pParse->pNewTable; iDb = pTab->iDb; } + pDb = &db->aDb[iDb]; if( pTab==0 || pParse->nErr ) goto exit_create_index; if( pTab->readOnly ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -2181,11 +2190,11 @@ if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !db->init.busy ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; - if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){ + if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); goto exit_create_index; } if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); @@ -2205,11 +2214,11 @@ /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = db->aDb[iDb].zName; + const char *zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; @@ -2226,54 +2235,77 @@ if( pList==0 ){ nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName; nullId.n = strlen((char*)nullId.z); pList = sqlite3ExprListAppend(0, 0, &nullId); if( pList==0 ) goto exit_create_index; + pList->a[0].sortOrder = sortOrder; } /* ** Allocate the index structure. */ - pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) + - (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr ); + nName = strlen(zName); + pIndex = sqliteMalloc( sizeof(Index) + nName + 2 + sizeof(int) + + (sizeof(int)*2 + sizeof(CollSeq*) + 1)*pList->nExpr ); if( sqlite3Tsd()->mallocFailed ) goto exit_create_index; pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr]; pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr]; pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1]; + pIndex->keyInfo.aSortOrder = &pIndex->zName[nName+1]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; pIndex->onError = onError; pIndex->autoIndex = pName==0; pIndex->iDb = iDb; + + /* Check to see if we should honor DESC requests on index columns + */ + if( pDb->file_format>=4 || (pDb->descIndex && db->init.busy) ){ +#if 0 + sortOrderMask = -1; /* Honor DESC */ +#else + sortOrderMask = 0; +#endif + }else{ + sortOrderMask = 0; /* Ignore DESC */ + } /* 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; inExpr; i++){ - for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; + for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ + const char *zColName = pListItem->zName; + Column *pTabCol; + int sortOrder; + for(j=0, pTabCol=pTab->aCol; jnCol; j++, pTabCol++){ + if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; } if( j>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "table %s has no column named %s", - pTab->zName, pList->a[i].zName); + pTab->zName, zColName); goto exit_create_index; } pIndex->aiColumn[i] = j; - if( pList->a[i].pExpr ){ - assert( pList->a[i].pExpr->pColl ); - pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl; + if( pListItem->pExpr ){ + assert( pListItem->pExpr->pColl ); + pIndex->keyInfo.aColl[i] = pListItem->pExpr->pColl; }else{ pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; } assert( pIndex->keyInfo.aColl[i] ); if( !db->init.busy && sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i]) ){ goto exit_create_index; } + sortOrder = pListItem->sortOrder; + pDb->descIndex |= sortOrder; + sortOrder &= sortOrderMask; + pIndex->keyInfo.aSortOrder[i] = sortOrder; + descSeen |= sortOrder; } pIndex->keyInfo.nField = pList->nExpr; sqlite3DefaultRowEst(pIndex); if( pTab==pParse->pNewTable ){ @@ -2299,10 +2331,11 @@ if( pIdx->nColumn!=pIndex->nColumn ) continue; for(k=0; knColumn; k++){ if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break; + if( pIdx->keyInfo.aSortOrder[k]!=pIndex->keyInfo.aSortOrder[k] ) break; } if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. @@ -2361,10 +2394,15 @@ char *zStmt; int iMem = pParse->nMem++; v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; + + /* Make sure the file_format is at least 4 if we have DESC indices. */ + if( descSeen ){ + sqlite3MinimumFileFormat(pParse, iDb, 4); + } /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0); Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -12,11 +12,11 @@ ** 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.187 2005/12/09 20:02:05 drh Exp $ +** @(#) $Id: parse.y,v 1.188 2005/12/16 01:06:17 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ @@ -255,13 +255,13 @@ // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} -ccons ::= PRIMARY KEY sortorder onconf(R) autoinc(I). - {sqlite3AddPrimaryKey(pParse,0,R,I);} -ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);} +ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). + {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} +ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);} ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, (char*)C.z, C.n);} @@ -305,13 +305,13 @@ conslist ::= conslist COMMA tcons. conslist ::= conslist tcons. conslist ::= tcons. tcons ::= CONSTRAINT nm. tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R). - {sqlite3AddPrimaryKey(pParse,X,R,I);} + {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP idxlist(X) RP onconf(R). - {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);} + {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0);} tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);} tcons ::= FOREIGN KEY LP idxlist(FA) RP REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); @@ -832,11 +832,12 @@ // cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D) ON nm(Y) LP idxlist(Z) RP(E) onconf(R). { if( U!=OE_None ) U = R; if( U==OE_Default) U = OE_Abort; - sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0),Z,U, &S, &E); + sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0), Z, U, + &S, &E, SQLITE_SO_ASC); } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} @@ -847,25 +848,27 @@ %destructor idxlist_opt {sqlite3ExprListDelete($$);} %type idxitem {Token} idxlist_opt(A) ::= . {A = 0;} idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;} -idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder. { +idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder(Z). { Expr *p = 0; if( C.n>0 ){ p = sqlite3Expr(TK_COLUMN, 0, 0, 0); if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n); } A = sqlite3ExprListAppend(X, p, &Y); + if( A ) A->a[A->nExpr-1].sortOrder = Z; } -idxlist(A) ::= idxitem(Y) collate(C) sortorder. { +idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). { Expr *p = 0; if( C.n>0 ){ p = sqlite3Expr(TK_COLUMN, 0, 0, 0); if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n); } A = sqlite3ExprListAppend(0, p, &Y); + if( A ) A->a[A->nExpr-1].sortOrder = Z; } idxitem(A) ::= nm(X). {A = X;} ///////////////////////////// The DROP INDEX command ///////////////////////// Index: src/prepare.c ================================================================== --- src/prepare.c +++ src/prepare.c @@ -11,11 +11,11 @@ ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.9 2005/12/15 03:04:11 drh Exp $ +** $Id: prepare.c,v 1.10 2005/12/16 01:06:17 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -113,10 +113,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ int rc; BtCursor *curMain; int size; Table *pTab; + Db *pDb; char const *azArg[5]; char zDbNum[30]; int meta[10]; InitData initData; char const *zMasterSchema; @@ -182,15 +183,16 @@ } sqlite3SafetyOn(db); /* Create a cursor to hold the database open */ - if( db->aDb[iDb].pBt==0 ){ + pDb = &db->aDb[iDb]; + if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded); return SQLITE_OK; } - rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain); + rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain); if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); return rc; } @@ -212,21 +214,21 @@ ** the possible values of meta[4]. */ if( rc==SQLITE_OK ){ int i; for(i=0; rc==SQLITE_OK && iaDb[iDb].pBt, i+1, (u32 *)&meta[i]); + rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); } if( rc ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeCloseCursor(curMain); return rc; } }else{ memset(meta, 0, sizeof(meta)); } - db->aDb[iDb].schema_cookie = meta[0]; + pDb->schema_cookie = meta[0]; /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. @@ -247,43 +249,29 @@ } } size = meta[2]; if( size==0 ){ size = MAX_PAGES; } - db->aDb[iDb].cache_size = size; - - if( iDb==0 ){ - db->file_format = meta[1]; - if( db->file_format==0 ){ - /* This happens if the database was initially empty */ - db->file_format = 1; - } - - if( db->file_format==2 || db->file_format==3 ){ - /* File format 2 is treated exactly as file format 1. New - ** databases are created with file format 1. - */ - db->file_format = 1; - } - } + pDb->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); /* ** file_format==1 Version 3.0.0. - ** file_format==2 Version 3.1.3. - ** file_format==3 Version 3.1.4. - ** - ** Version 3.0 can only use files with file_format==1. Version 3.1.3 - ** can read and write files with file_format==1 or file_format==2. - ** Version 3.1.4 can read and write file formats 1, 2 and 3. + ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN + ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults + ** file_format==4 Version 3.3.0. // DESC indices */ - if( meta[1]>3 ){ + pDb->file_format = meta[1]; + if( pDb->file_format==0 ){ + pDb->file_format = 1; + } + if( pDb->file_format>4 ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } - sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size); /* Read the schema information out of the schema tables */ assert( db->init.busy ); if( rc==SQLITE_EMPTY ){ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.437 2005/12/15 15:22:09 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.438 2005/12/16 01:06:17 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* @@ -354,10 +354,12 @@ Hash trigHash; /* All triggers indexed by name */ Hash aFKey; /* Foreign keys indexed by to-table */ u16 flags; /* Flags associated with this database */ u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ u8 safety_level; /* How aggressive at synching data to disk */ + u8 file_format; /* Schema format version for this file */ + u8 descIndex; /* True if any index uses the DESC attribute */ int cache_size; /* Number of pages to use in the cache */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ void *pAux; /* Auxiliary data. Usually NULL */ void (*xFreeAux)(void*); /* Routine to free pAux */ }; @@ -417,11 +419,10 @@ Db *aDb; /* All backends */ int flags; /* Miscellanous flags. See below */ int errCode; /* Most recent error code (SQLITE_*) */ u8 enc; /* Text encoding for this database. */ u8 autoCommit; /* The auto-commit flag. */ - u8 file_format; /* What file format version is this database? */ u8 temp_store; /* 1: file 2: memory 0: default */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 priorNewRowid; /* Last randomly generated ROWID */ @@ -1465,11 +1466,11 @@ Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*); void sqlite3OpenMasterTable(Vdbe *v, int); void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); -void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int); +void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); void sqlite3AddCheckConstraint(Parse*, Expr*); void sqlite3AddColumnType(Parse*,Token*); void sqlite3AddDefaultValue(Parse*,Expr*); void sqlite3AddCollateType(Parse*, const char*, int); void sqlite3EndTable(Parse*,Token*,Token*,Select*); @@ -1491,11 +1492,11 @@ void sqlite3SrcListAddAlias(SrcList*, Token*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(IdList*); void sqlite3SrcListDelete(SrcList*); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, - Token*); + Token*, int); void sqlite3DropIndex(Parse*, SrcList*); void sqlite3AddKeyType(Vdbe*, ExprList*); void sqlite3AddIdxKeyType(Vdbe*, Index*); int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff); Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, @@ -1674,10 +1675,11 @@ void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); SqliteTsd *sqlite3Tsd(); void sqlite3AttachFunctions(sqlite3 *); +void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3MallocClearFailed(); #ifdef NDEBUG #define sqlite3MallocDisallow() #define sqlite3MallocAllow() Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -433,20 +433,22 @@ pOp->p3type = P3_NOTUSED; }else if( n==P3_KEYINFO ){ KeyInfo *pKeyInfo; int nField, nByte; - /* KeyInfo structures that include an KeyInfo.aSortOrder are always - ** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array - ** is not duplicated when P3_KEYINFO is used. */ - /* assert( pKeyInfo->aSortOrder==0 ); */ nField = ((KeyInfo*)zP3)->nField; - nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]); + nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; pKeyInfo = sqliteMallocRaw( nByte ); pOp->p3 = (char*)pKeyInfo; if( pKeyInfo ){ + char *aSortOrder; memcpy(pKeyInfo, zP3, nByte); + aSortOrder = pKeyInfo->aSortOrder; + if( aSortOrder ){ + pKeyInfo->aSortOrder = (char*)&pKeyInfo->aColl[nField]; + memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); + } pOp->p3type = P3_KEYINFO; }else{ pOp->p3type = P3_NOTUSED; } }else if( n==P3_KEYINFO_HANDOFF ){ Index: test/capi3.test ================================================================== --- test/capi3.test +++ test/capi3.test @@ -9,11 +9,11 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.34 2005/08/11 02:10:19 drh Exp $ +# $Id: capi3.test,v 1.35 2005/12/16 01:06:18 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -488,11 +488,11 @@ # Do this by updating the file format via the btree layer. do_test capi3-7.1 { set ::bt [btree_open test.db 10 0] btree_begin_transaction $::bt set meta [btree_get_meta $::bt] - lset meta 2 4 + lset meta 2 5 eval [concat btree_update_meta $::bt [lrange $meta 0 end]] btree_commit $::bt btree_close $::bt } {} do_test capi3-7.2 {