aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alter.c25
-rw-r--r--src/build.c88
-rw-r--r--src/parse.y21
-rw-r--r--src/prepare.c46
-rw-r--r--src/sqliteInt.h10
-rw-r--r--src/vdbeaux.c12
6 files changed, 121 insertions, 81 deletions
diff --git a/src/alter.c b/src/alter.c
index 1e4f8a274..6758315d1 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -12,7 +12,7 @@
** 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 <ctype.h>
@@ -462,19 +462,26 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** 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);
+ sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
- /* Only set the file format to $f if it is currently less than $f. */
+ /* 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, f, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Integer, f, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
}
-
- /* Reload the schema of the modified table. */
- reloadTableSchema(pParse, pTab, pTab->zName);
}
diff --git a/src/build.c b/src/build.c
index 2a9a144c5..32d4bfd05 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
** 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 <ctype.h>
@@ -764,7 +764,7 @@ void sqlite3StartTable(
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);
@@ -1010,7 +1010,8 @@ 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;
@@ -1041,7 +1042,8 @@ void sqlite3AddPrimaryKey(
if( iCol>=0 && iCol<pTab->nCol ){
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;
@@ -1051,7 +1053,7 @@ void sqlite3AddPrimaryKey(
"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;
}
@@ -2094,18 +2096,24 @@ void sqlite3CreateIndex(
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;
@@ -2148,6 +2156,7 @@ void sqlite3CreateIndex(
pTab = pParse->pNewTable;
iDb = pTab->iDb;
}
+ pDb = &db->aDb[iDb];
if( pTab==0 || pParse->nErr ) goto exit_create_index;
if( pTab->readOnly ){
@@ -2183,7 +2192,7 @@ void sqlite3CreateIndex(
}
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;
}
@@ -2207,7 +2216,7 @@ void sqlite3CreateIndex(
*/
#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;
}
@@ -2228,17 +2237,20 @@ void sqlite3CreateIndex(
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;
@@ -2246,23 +2258,38 @@ void sqlite3CreateIndex(
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; i<pList->nExpr; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
+ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
+ const char *zColName = pListItem->zName;
+ Column *pTabCol;
+ int sortOrder;
+ for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; 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;
}
@@ -2272,6 +2299,11 @@ void sqlite3CreateIndex(
){
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);
@@ -2301,6 +2333,7 @@ void sqlite3CreateIndex(
for(k=0; k<pIdx->nColumn; 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 ){
@@ -2364,6 +2397,11 @@ void sqlite3CreateIndex(
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);
diff --git a/src/parse.y b/src/parse.y
index 64f3a7beb..f000a6ffd 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** 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_"
@@ -257,9 +257,9 @@ carg ::= DEFAULT id(X). {
//
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);}
@@ -307,9 +307,9 @@ 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). {
@@ -834,7 +834,8 @@ 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}
@@ -849,21 +850,23 @@ uniqueflag(A) ::= . {A = OE_None;}
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;}
diff --git a/src/prepare.c b/src/prepare.c
index ca00049e6..f530dd874 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -13,7 +13,7 @@
** 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"
@@ -115,6 +115,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
BtCursor *curMain;
int size;
Table *pTab;
+ Db *pDb;
char const *azArg[5];
char zDbNum[30];
int meta[10];
@@ -184,11 +185,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
/* 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;
@@ -214,7 +216,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
if( rc==SQLITE_OK ){
int i;
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
- rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, i+1, (u32 *)&meta[i]);
+ rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
if( rc ){
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
@@ -224,7 +226,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}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.
@@ -249,39 +251,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
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
*/
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5cd15242b..0285677f8 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** 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_
@@ -356,6 +356,8 @@ struct Db {
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 */
@@ -419,7 +421,6 @@ struct sqlite3 {
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) */
@@ -1467,7 +1468,7 @@ 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*);
@@ -1493,7 +1494,7 @@ 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*);
@@ -1676,6 +1677,7 @@ void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
SqliteTsd *sqlite3Tsd();
void sqlite3AttachFunctions(sqlite3 *);
+void sqlite3MinimumFileFormat(Parse*, int, int);
void sqlite3MallocClearFailed();
#ifdef NDEBUG
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index f435effa6..6949f8c35 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -435,16 +435,18 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
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;