1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

(1) Modifications to the user-function interface and (2) Internal changes

to automatically created indices. (CVS 1575)

FossilOrigin-Name: 5903f53828b5d282b33e27813417e4317c9ecf0b
This commit is contained in:
danielk1977
2004-06-12 09:25:12 +00:00
parent 3cde3bb0da
commit d8123366c4
23 changed files with 618 additions and 337 deletions

View File

@ -1,5 +1,5 @@
C Bug\sfix\sin\sthe\sunix\slocking\scode.\s(CVS\s1574) C (1)\sModifications\sto\sthe\suser-function\sinterface\sand\s(2)\sInternal\schanges\nto\sautomatically\screated\sindices.\s(CVS\s1575)
D 2004-06-12T02:17:15 D 2004-06-12T09:25:12
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -28,18 +28,18 @@ F src/attach.c 93b8ecec4a8d7b4e9f2479e2327d90c9d01765e8
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584 F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
F src/build.c 1943d5910d0a9807dd788758c41c5b1900a8da78 F src/build.c 916a84fa5f8bfd44dbe14c3d7c923dd07ee7373f
F src/date.c 2d193dbe7ca0d68a81be0ed64fb455b61ceb420d F src/date.c 65b483caeb0e4dd663667d2f927caa058168ebff
F src/delete.c 911221aadb35d610c84fadb32e71c52990827e58 F src/delete.c 911221aadb35d610c84fadb32e71c52990827e58
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c 03ab3de3897a89c4b4fce4438566e8fef1d973f7 F src/expr.c f9eafe34828ebc9040b4f0f4de2c1e6a0aee296b
F src/func.c a58fef26514e26f49312785d2fde370e3a8a85a4 F src/func.c 3b86bf207b21c1eff766c06c67a0712e756873e5
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
F src/insert.c 68c7f3ddd6a7f1e5596d6996da1a2861b3789a3a F src/insert.c 68c7f3ddd6a7f1e5596d6996da1a2861b3789a3a
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
F src/main.c 86b0946b5d99d4c42437d50494732a316025d141 F src/main.c 9061fff2b04759d849155a334bf2a9f158d325d7
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 F src/md5.c d77a389955759c8329bb357e3d71bac3d6eb710b
F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380 F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380
F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348 F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348
F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0 F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0
@ -54,29 +54,29 @@ F src/parse.y 097438674976355a10cf177bd97326c548820b86
F src/pragma.c e288bd122d3ca41ec2032475abde1ff5fa3095f4 F src/pragma.c e288bd122d3ca41ec2032475abde1ff5fa3095f4
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8 F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c d29488f86e61e0d45dff318e1f04ba6a7e5782d0 F src/select.c 164d1a68b3cc3c6a53ca9632a47ccbf9fde267b8
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469 F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
F src/sqlite.h.in a4bee5b5c96d8a19f62c750b370bb05ab9073871 F src/sqlite.h.in 36c253844656186ca53e1999efa6ef7b44f88779
F src/sqliteInt.h 289523cf5337316d85be9b1bb9a067f1d52f80e5 F src/sqliteInt.h 924f0bcb493722c90cec7b19a240a37a4f01bbe7
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
F src/tclsqlite.c 689e47545c55dd70e537c1048da47555cb7790ea F src/tclsqlite.c f094cc80cdbc87178c1e28db7749e8770b301554
F src/test1.c 5f5c0773df1091cc02ddf6608a8f6e0c65940a56 F src/test1.c e7588e3e55f7595c76874a4b9c6365e891ac69d1
F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9 F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9
F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2 F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
F src/test5.c 13ac1db35b03acbc197ceb245fe862da5ebf2369 F src/test5.c 13ac1db35b03acbc197ceb245fe862da5ebf2369
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
F src/trigger.c d1a4d7a59b34c811bf6070d64d0497baa0140dcf F src/trigger.c 3ff6f24e5273767117126b712eaae24c3d6466aa
F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38 F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38
F src/utf.c e16737b3fc4201bf7ce9bd8ced5250596aa31b76 F src/utf.c e16737b3fc4201bf7ce9bd8ced5250596aa31b76
F src/util.c 90375fa253137562d536ccdd40b297f0fd7413fc F src/util.c 90375fa253137562d536ccdd40b297f0fd7413fc
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
F src/vdbe.c 230613d7524024c99a30fd67bd16bda0860878fe F src/vdbe.c 026b78bc404a2585aaefbf876295ed3ae892d769
F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
F src/vdbeInt.h 57b7001bc18de348f2180c5fa8a85b687592a19b F src/vdbeInt.h c4ff480cd8f859c9862d759aebd0fe5ebaef47a1
F src/vdbeapi.c d7803664ea8bacc109ddb4b96ce8c5785ff60138 F src/vdbeapi.c ee350b552fc4c1c695b760f914f69e9c5556e829
F src/vdbeaux.c fefea411bd41ac46fada191d017a414817f7d86b F src/vdbeaux.c 1d0dbaf73c89bd1cc27abad19ee0aa26ab5d03f4
F src/vdbemem.c 26cd5419a9c9e7a8959618376f04afdb433b77a3 F src/vdbemem.c 34f59988831ea032b7f526c2c73175f9f4c0f3ad
F src/where.c dda77afaa593cd54e5955ec433076de18faf62f6 F src/where.c dda77afaa593cd54e5955ec433076de18faf62f6
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/attach.test aed659e52635662bcd5069599aaca823533edf5a F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
@ -109,14 +109,14 @@ F test/enc.test a55481d45ff493804e8d88357feb4642fc50a6b2
F test/enc2.test 1d469f58ee7f187bf06e11bd72a12bdea6362b2f F test/enc2.test 1d469f58ee7f187bf06e11bd72a12bdea6362b2f
F test/expr.test 521588701dae8cf5aa2b8a18c5c897711f754332 F test/expr.test 521588701dae8cf5aa2b8a18c5c897711f754332
F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7 F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7
F test/func.test 9816fbed0a5e87e00f4fc88b4cdcd638abc524c4 F test/func.test a63cf7a16bbd9dd1430214f6a0625099faa530f3
F test/hook.test c4102c672d67f8fb60ea459842805abcba69a747 F test/hook.test c4102c672d67f8fb60ea459842805abcba69a747
F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a
F test/index.test ad3f479a3dc4a6d9105a2c88e3ee432498441c34 F test/index.test 4d2e73647872b540df4335387cc91faff4365020
F test/insert.test 6ec324659656f4a86e4abfcf1a1fd2795ba6b603 F test/insert.test 6ec324659656f4a86e4abfcf1a1fd2795ba6b603
F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91 F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
F test/intpkey.test e93d739c8a49f5f63748d4ed1c8084c33dc4c0a1 F test/intpkey.test e6e0d7cca0e64ec09cbf683a4712ed2196073742
F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4 F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4
F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd
F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
@ -151,7 +151,7 @@ F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8 F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
F test/table.test 1defd90e8200661a822618b18748b9339a7fef2f F test/table.test bbae9f267e947963f8951e72516667ab16c5810c
F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1 F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
F test/tclsqlite.test 2ff5abfd1e133cddcfc61ad5850e3b93f4a7ff40 F test/tclsqlite.test 2ff5abfd1e133cddcfc61ad5850e3b93f4a7ff40
F test/temptable.test 6809810546311140f1f4efb4a4fc679b36495f50 F test/temptable.test 6809810546311140f1f4efb4a4fc679b36495f50
@ -223,7 +223,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 4f1cfca5ca703d0068cf8d6222dc8e0cfb7e24b6 P dcad244f58453d23f2bcb749dcea077434bbd08c
R 5ae96fc36d6708ebd2e3e17bdca09c44 R 5693485a98aab5da11e93316c0299999
U drh U danielk1977
Z 179ef88834f751e9c7fc73c1211cbbf2 Z 4d571fd8206bcad58754dc2ba435cca7

View File

@ -1 +1 @@
dcad244f58453d23f2bcb749dcea077434bbd08c 5903f53828b5d282b33e27813417e4317c9ecf0b

View File

@ -23,7 +23,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.217 2004/06/12 00:42:35 danielk1977 Exp $ ** $Id: build.c,v 1.218 2004/06/12 09:25:12 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -479,6 +479,21 @@ int sqlite3TwoPartName(
return iDb; return iDb;
} }
/*
** This routine is used to check if the UTF-8 string zName is a legal
** unqualified name for a new schema object (table, index, view or
** trigger). All names are legal except those that begin with the string
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
** is reserved for internal use.
*/
int sqlite3CheckObjectName(Parse *pParse, const char *zName){
if( !pParse->db->init.busy && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
return SQLITE_ERROR;
}
return SQLITE_OK;
}
/* /*
** Begin constructing a new table representation in memory. This is ** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response ** the first of several action routines that get called in response
@ -541,6 +556,9 @@ void sqlite3StartTable(
pParse->sNameToken = *pName; pParse->sNameToken = *pName;
zName = sqlite3TableNameFromToken(pName); zName = sqlite3TableNameFromToken(pName);
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
return;
}
if( zName==0 ) return; if( zName==0 ) return;
if( db->init.iDb==1 ) isTemp = 1; if( db->init.iDb==1 ) isTemp = 1;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
@ -1854,7 +1872,7 @@ void sqlite3CreateIndex(
Token *pEnd /* The ")" that closes the CREATE INDEX statement */ Token *pEnd /* The ")" that closes the CREATE INDEX statement */
){ ){
Table *pTab = 0; /* Table to be indexed */ Table *pTab = 0; /* Table to be indexed */
Index *pIndex; /* The index to be created */ Index *pIndex = 0; /* The index to be created */
char *zName = 0; char *zName = 0;
int i, j; int i, j;
Token nullId; /* Fake token for an empty ID list */ Token nullId; /* Fake token for an empty ID list */
@ -1927,30 +1945,33 @@ void sqlite3CreateIndex(
** dealing with a primary key or UNIQUE constraint. We have to invent our ** dealing with a primary key or UNIQUE constraint. We have to invent our
** own name. ** own name.
*/ */
if( pName && !db->init.busy ){ if( pName ){
Index *pISameName; /* Another index with the same name */ zName = sqlite3TableNameFromToken(pName);
Table *pTSameName; /* A table with same name as the index */
zName = sqliteStrNDup(pName->z, pName->n);
if( zName==0 ) goto exit_create_index; if( zName==0 ) goto exit_create_index;
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){ if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
goto exit_create_index; goto exit_create_index;
} }
if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){ if( !db->init.busy ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); Index *pISameName; /* Another index with the same name */
goto exit_create_index; Table *pTSameName; /* A table with same name as the index */
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
goto exit_create_index;
}
if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
} }
}else if( pName==0 ){ }else if( pName==0 ){
char zBuf[30]; char zBuf[30];
int n; int n;
Index *pLoop; Index *pLoop;
for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
sprintf(zBuf,"%d)",n); sprintf(zBuf,"_%d",n);
zName = 0; zName = 0;
sqlite3SetString(&zName, "(", pTab->zName, " autoindex ", zBuf, (char*)0); sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0);
if( zName==0 ) goto exit_create_index; if( zName==0 ) goto exit_create_index;
}else{
zName = sqliteStrNDup(pName->z, pName->n);
} }
/* Check for authorization to create an index. /* Check for authorization to create an index.
@ -2006,7 +2027,6 @@ void sqlite3CreateIndex(
if( j>=pTab->nCol ){ if( j>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "table %s has no column named %s", sqlite3ErrorMsg(pParse, "table %s has no column named %s",
pTab->zName, pList->a[i].zName); pTab->zName, pList->a[i].zName);
sqliteFree(pIndex);
goto exit_create_index; goto exit_create_index;
} }
pIndex->aiColumn[i] = j; pIndex->aiColumn[i] = j;
@ -2025,6 +2045,46 @@ void sqlite3CreateIndex(
} }
pIndex->keyInfo.nField = pList->nExpr; pIndex->keyInfo.nField = pList->nExpr;
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
** a PRIMARY KEY or UNIQUE clause following the column definitions.
** i.e. one of:
**
** CREATE TABLE t(x PRIMARY KEY, y);
** CREATE TABLE t(x, y, UNIQUE(x, y));
**
** Either way, check to see if the table already has such an index. If
** so, don't bother creating this one. This only applies to
** automatically created indices. Users can do as they wish with
** explicit indices.
*/
Index *pIdx;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int k;
assert( pIdx->onError!=OE_None );
assert( pIdx->autoIndex );
assert( pIndex->onError!=OE_None );
if( pIdx->nColumn!=pIndex->nColumn ) continue;
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( k==pIdx->nColumn ){
/* FIX ME: It's possible the onError of the old index should be
** adjusted. For example in the statement:
**
** CREATE TABLE t (x UNIQUE, UNIQUE(x) ON CONFLICT ROLLBACK);
**
** The Index.onError should be upgraded from OE_Abort to
** OE_Rollback when the second UNIQUE is parsed.
*/
goto exit_create_index;
}
}
}
/* Link the new Index structure to its table and to the other /* Link the new Index structure to its table and to the other
** in-memory database structures. ** in-memory database structures.
*/ */
@ -2034,30 +2094,11 @@ void sqlite3CreateIndex(
pIndex->zName, strlen(pIndex->zName)+1, pIndex); pIndex->zName, strlen(pIndex->zName)+1, pIndex);
if( p ){ if( p ){
assert( p==pIndex ); /* Malloc must have failed */ assert( p==pIndex ); /* Malloc must have failed */
sqliteFree(pIndex);
goto exit_create_index; goto exit_create_index;
} }
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
/* When adding an index to the list of indices for a table, make
** sure all indices labeled OE_Replace come after all those labeled
** OE_Ignore. This is necessary for the correct operation of UPDATE
** and INSERT.
*/
if( onError!=OE_Replace || pTab->pIndex==0
|| pTab->pIndex->onError==OE_Replace){
pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex;
}else{
Index *pOther = pTab->pIndex;
while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
pOther = pOther->pNext;
}
pIndex->pNext = pOther->pNext;
pOther->pNext = pIndex;
}
/* If the db->init.busy is 1 it means we are reading the SQL off the /* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" table on the disk. So do not write to the disk ** "sqlite_master" table on the disk. So do not write to the disk
** again. Extract the table number from the db->init.newTnum field. ** again. Extract the table number from the db->init.newTnum field.
@ -2145,8 +2186,28 @@ void sqlite3CreateIndex(
} }
} }
/* When adding an index to the list of indices for a table, make
** sure all indices labeled OE_Replace come after all those labeled
** OE_Ignore. This is necessary for the correct operation of UPDATE
** and INSERT.
*/
if( onError!=OE_Replace || pTab->pIndex==0
|| pTab->pIndex->onError==OE_Replace){
pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex;
}else{
Index *pOther = pTab->pIndex;
while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
pOther = pOther->pNext;
}
pIndex->pNext = pOther->pNext;
pOther->pNext = pIndex;
}
pIndex = 0;
/* Clean up before exiting */ /* Clean up before exiting */
exit_create_index: exit_create_index:
if( pIndex ) sqliteFree(pIndex);
sqlite3ExprListDelete(pList); sqlite3ExprListDelete(pList);
/* sqlite3SrcListDelete(pTable); */ /* sqlite3SrcListDelete(pTable); */
sqliteFree(zName); sqliteFree(zName);

View File

@ -16,7 +16,7 @@
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: date.c,v 1.28 2004/06/12 00:42:35 danielk1977 Exp $ ** $Id: date.c,v 1.29 2004/06/12 09:25:14 danielk1977 Exp $
** **
** NOTES: ** NOTES:
** **
@ -692,7 +692,7 @@ static void datetimeFunc(
computeYMD_HMS(&x); computeYMD_HMS(&x);
sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m, sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
(int)(x.s)); (int)(x.s));
sqlite3_result_text(context, zBuf, -1, 1); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }
} }
@ -711,7 +711,7 @@ static void timeFunc(
char zBuf[100]; char zBuf[100];
computeHMS(&x); computeHMS(&x);
sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
sqlite3_result_text(context, zBuf, -1, 1); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }
} }
@ -730,7 +730,7 @@ static void dateFunc(
char zBuf[100]; char zBuf[100];
computeYMD(&x); computeYMD(&x);
sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
sqlite3_result_text(context, zBuf, -1, 1); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }
} }
@ -854,7 +854,7 @@ static void strftimeFunc(
} }
} }
z[j] = 0; z[j] = 0;
sqlite3_result_text(context, z, -1, 1); sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
if( z!=zBuf ){ if( z!=zBuf ){
sqliteFree(z); sqliteFree(z);
} }
@ -885,7 +885,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite *db){
int i; int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, 0, 0, 0, sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].xFunc, 0, 0); SQLITE_UTF8, 0, 0, aFuncs[i].xFunc, 0, 0);
} }
} }

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite. ** for generating VDBE code that evaluates expressions in SQLite.
** **
** $Id: expr.c,v 1.140 2004/06/12 00:42:35 danielk1977 Exp $ ** $Id: expr.c,v 1.141 2004/06/12 09:25:14 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -1012,12 +1012,12 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
int nId; /* Number of characters in function name */ int nId; /* Number of characters in function name */
const char *zId; /* The function name. */ const char *zId; /* The function name. */
FuncDef *pDef; FuncDef *pDef;
int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; int enc = pParse->db->enc;
getFunctionName(pExpr, &zId, &nId); getFunctionName(pExpr, &zId, &nId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, iPrefEnc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){ if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, iPrefEnc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
if( pDef==0 ){ if( pDef==0 ){
no_such_func = 1; no_such_func = 1;
}else{ }else{
@ -1280,10 +1280,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
const char *zId; const char *zId;
int p2 = 0; int p2 = 0;
int i; int i;
int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; u8 enc = pParse->db->enc;
CollSeq *pColl = 0; CollSeq *pColl = 0;
getFunctionName(pExpr, &zId, &nId); getFunctionName(pExpr, &zId, &nId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, iPrefEnc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
assert( pDef!=0 ); assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList); nExpr = sqlite3ExprCodeExprList(pParse, pList);
for(i=0; i<nExpr && i<32; i++){ for(i=0; i<nExpr && i<32; i++){
@ -1296,7 +1296,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
} }
if( pDef->needCollSeq ){ if( pDef->needCollSeq ){
if( !pColl ) pColl = pParse->db->pDfltColl; if( !pColl ) pColl = pParse->db->pDfltColl;
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, pColl, P3_COLLSEQ); sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
} }
sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF); sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
break; break;
@ -1724,14 +1724,14 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
} }
} }
if( i>=pParse->nAgg ){ if( i>=pParse->nAgg ){
int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; u8 enc = pParse->db->enc;
i = appendAggInfo(pParse); i = appendAggInfo(pParse);
if( i<0 ) return 1; if( i<0 ) return 1;
pParse->aAgg[i].isAgg = 1; pParse->aAgg[i].isAgg = 1;
pParse->aAgg[i].pExpr = pExpr; pParse->aAgg[i].pExpr = pExpr;
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
pExpr->token.z, pExpr->token.n, pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, iPrefEnc, 0); pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
} }
pExpr->iAgg = i; pExpr->iAgg = i;
break; break;
@ -1781,53 +1781,68 @@ FuncDef *sqlite3FindFunction(
const char *zName, /* Name of the function. Not null-terminated */ const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */ int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */ int nArg, /* Number of arguments. -1 means any number */
int eTextRep, /* True to retrieve UTF-16 versions. */ u8 enc, /* Preferred text encoding */
int createFlag /* Create new entry if true and does not otherwise exist */ int createFlag /* Create new entry if true and does not otherwise exist */
){ ){
FuncDef *p; /* Iterator variable */ FuncDef *p; /* Iterator variable */
FuncDef *pFirst; /* First function with this name */ FuncDef *pFirst; /* First function with this name */
FuncDef *pBest = 0; /* Best match found so far */ FuncDef *pBest = 0; /* Best match found so far */
int matchqual = 0; int bestmatch = 0;
/* Normalize argument values to simplify comparisons below. */
if( eTextRep ) eTextRep = 1; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
if( nArg<-1 ) nArg = -1; if( nArg<-1 ) nArg = -1;
pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
for(p=pFirst; p; p=p->pNext){ for(p=pFirst; p; p=p->pNext){
if( 1 || p->xFunc || p->xStep ){ /* During the search for the best function definition, bestmatch is set
if( p->nArg==nArg && p->iPrefEnc==eTextRep ){ ** as follows to indicate the quality of the match with the definition
/* A perfect match. */ ** pointed to by pBest:
pBest = p; **
matchqual = 4; ** 0: pBest is NULL. No match has been found.
break; ** 1: A variable arguments function that prefers UTF-8 when a UTF-16
** encoding is requested, or vice versa.
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
** requested, or vice versa.
** 3: A variable arguments function using the same text encoding.
** 4: A function with the exact number of arguments requested that
** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
** 5: A function with the exact number of arguments requested that
** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
** 6: An exact match.
**
** A larger value of 'matchqual' indicates a more desirable match.
*/
if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){
int match = 1; /* Quality of this match */
if( p->nArg==nArg || nArg==-1 ){
match = 4;
} }
if( p->nArg==nArg ){ if( enc==p->iPrefEnc ){
/* Number of arguments matches, but not the text encoding */ match += 2;
pBest = p;
matchqual = 3;
} }
else if( (p->nArg<0) || (nArg<0) ){ else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
if( matchqual<2 && p->iPrefEnc==eTextRep ){ (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
/* Matched a varargs function with correct text encoding */ match += 1;
pBest = p; }
matchqual = 2;
} if( match>bestmatch ){
if( matchqual<1 ){ pBest = p;
/* Matched a varargs function with incorrect text encoding */ bestmatch = match;
pBest = p;
matchqual = 1;
}
} }
} }
} }
if( createFlag && matchqual<4 && /* If the createFlag parameter is true, and the seach did not reveal an
** exact match for the name, number of arguments and encoding, then add a
** new entry to the hash table and return it.
*/
if( createFlag && bestmatch<6 &&
(pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){ (pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){
pBest->nArg = nArg; pBest->nArg = nArg;
pBest->pNext = pFirst; pBest->pNext = pFirst;
pBest->zName = (char*)&pBest[1]; pBest->zName = (char*)&pBest[1];
pBest->iPrefEnc = eTextRep; pBest->iPrefEnc = enc;
memcpy(pBest->zName, zName, nName); memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0; pBest->zName[nName] = 0;
sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest); sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest);

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: func.c,v 1.67 2004/06/12 00:42:35 danielk1977 Exp $ ** $Id: func.c,v 1.68 2004/06/12 09:25:14 danielk1977 Exp $
*/ */
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
@ -75,7 +75,7 @@ static void typeofFunc(
case SQLITE_FLOAT: z = "real"; break; case SQLITE_FLOAT: z = "real"; break;
case SQLITE_BLOB: z = "blob"; break; case SQLITE_BLOB: z = "blob"; break;
} }
sqlite3_result_text(context, z, -1, 0); sqlite3_result_text(context, z, -1, SQLITE_STATIC);
} }
/* /*
@ -174,7 +174,7 @@ static void substrFunc(
} }
while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; } while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
if( p2<0 ) p2 = 0; if( p2<0 ) p2 = 0;
sqlite3_result_text(context, &z[p1], p2, 1); sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT);
} }
/* /*
@ -194,7 +194,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
r = sqlite3_value_double(argv[0]); r = sqlite3_value_double(argv[0]);
sprintf(zBuf,"%.*f",n,r); sprintf(zBuf,"%.*f",n,r);
sqlite3_result_text(context, zBuf, -1, 1); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }
/* /*
@ -210,7 +210,7 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
for(i=0; z[i]; i++){ for(i=0; z[i]; i++){
if( islower(z[i]) ) z[i] = toupper(z[i]); if( islower(z[i]) ) z[i] = toupper(z[i]);
} }
sqlite3_result_text(context, z, -1, 1); sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
sqliteFree(z); sqliteFree(z);
} }
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
@ -223,7 +223,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
for(i=0; z[i]; i++){ for(i=0; z[i]; i++){
if( isupper(z[i]) ) z[i] = tolower(z[i]); if( isupper(z[i]) ) z[i] = tolower(z[i]);
} }
sqlite3_result_text(context, z, -1, 1); sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
sqliteFree(z); sqliteFree(z);
} }
@ -586,7 +586,7 @@ static void versionFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
sqlite3_result_text(context, sqlite3_version, -1, 0); sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
} }
/* /*
@ -604,7 +604,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( argc<1 ) return; if( argc<1 ) return;
switch( sqlite3_value_type(argv[0]) ){ switch( sqlite3_value_type(argv[0]) ){
case SQLITE_NULL: { case SQLITE_NULL: {
sqlite3_result_text(context, "NULL", 4, 0); sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
break; break;
} }
case SQLITE_INTEGER: case SQLITE_INTEGER:
@ -634,7 +634,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
zText[(nBlob*2)+3] = '\0'; zText[(nBlob*2)+3] = '\0';
zText[0] = 'X'; zText[0] = 'X';
zText[1] = '\''; zText[1] = '\'';
sqlite3_result_text(context, zText, -1, 1); sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
sqliteFree(zText); sqliteFree(zText);
} }
break; break;
@ -656,7 +656,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
} }
z[j++] = '\''; z[j++] = '\'';
z[j] = 0; z[j] = 0;
sqlite3_result_text(context, z, j, 1); sqlite3_result_text(context, z, j, SQLITE_TRANSIENT);
sqliteFree(z); sqliteFree(z);
} }
} }
@ -695,9 +695,9 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
zResult[j++] = '0'; zResult[j++] = '0';
} }
zResult[j] = 0; zResult[j] = 0;
sqlite3_result_text(context, zResult, 4, 1); sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
}else{ }else{
sqlite3_result_text(context, "?000", 4, 0); sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
} }
} }
#endif #endif
@ -741,7 +741,49 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)]; zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
} }
zBuf[n] = 0; zBuf[n] = 0;
sqlite3_result_text(context, zBuf, n, 1); sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
/*
** The following two SQL functions are used to test returning a text
** result with a destructor. Function 'test_destructor' takes one argument
** and returns the same argument interpreted as TEXT. A destructor is
** passed with the sqlite3_result_text() call.
**
** SQL function 'test_destructor_count' returns the number of outstanding
** allocations made by 'test_destructor';
**
** WARNING: Not threadsafe.
*/
static int test_destructor_count_var = 0;
static void destructor(void *p){
char *zVal = (char *)p;
assert(zVal);
zVal--;
sqliteFree(zVal);
test_destructor_count_var--;
}
static void test_destructor(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
char *zVal;
test_destructor_count_var++;
assert( nArg==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
zVal = sqliteMalloc(sqlite3_value_bytes(argv[0]) + 2);
assert( zVal );
zVal++;
strcpy(zVal, sqlite3_value_text(argv[0]));
sqlite3_result_text(pCtx, zVal, -1, destructor);
}
static void test_destructor_count(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
sqlite3_result_int(pCtx, test_destructor_count_var);
} }
#endif #endif
@ -905,37 +947,40 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
u8 needCollSeq; u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **); void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = { } aFuncs[] = {
{ "min", -1, 0, 0, 1, minmaxFunc }, { "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
{ "min", 0, 0, 0, 1, 0 }, { "min", 0, 0, SQLITE_UTF8, 1, 0 },
{ "max", -1, 2, 0, 1, minmaxFunc }, { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc },
{ "max", 0, 2, 0, 1, 0 }, { "max", 0, 2, SQLITE_UTF8, 1, 0 },
{ "typeof", 1, 0, 0, 0, typeofFunc }, { "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
{ "length", 1, 0, 0, 0, lengthFunc }, { "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
{ "substr", 3, 0, 0, 0, substrFunc }, { "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
{ "abs", 1, 0, 0, 0, absFunc }, { "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
{ "round", 1, 0, 0, 0, roundFunc }, { "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
{ "round", 2, 0, 0, 0, roundFunc }, { "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
{ "upper", 1, 0, 0, 0, upperFunc }, { "upper", 1, 0, SQLITE_UTF8, 0, upperFunc },
{ "lower", 1, 0, 0, 0, lowerFunc }, { "lower", 1, 0, SQLITE_UTF8, 0, lowerFunc },
{ "coalesce", -1, 0, 0, 0, ifnullFunc }, { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
{ "coalesce", 0, 0, 0, 0, 0 }, { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
{ "coalesce", 1, 0, 0, 0, 0 }, { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
{ "ifnull", 2, 0, 0, 1, ifnullFunc }, { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, 0, 0, randomFunc }, { "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
{ "like", 2, 0, 0, 0, likeFunc }, /* UTF-8 */ { "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
{ "like", 2, 2, 1, 0, likeFunc }, /* UTF-16 */ { "like", 2, 2, SQLITE_UTF16,0, likeFunc },
{ "glob", 2, 0, 0, 0, globFunc }, { "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
{ "nullif", 2, 0, 0, 0, nullifFunc }, { "nullif", 2, 0, SQLITE_UTF8, 0, nullifFunc },
{ "sqlite_version", 0, 0, 0, 0, versionFunc}, { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, 0, 0, quoteFunc }, { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
{ "last_insert_rowid", 0, 1, 0, 0, last_insert_rowid }, { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "change_count", 0, 1, 0, 0, change_count }, { "change_count", 0, 1, SQLITE_UTF8, 0, change_count },
{ "last_statement_change_count", 0, 1, 0, 0, last_statement_change_count }, { "last_statement_change_count", 0, 1, SQLITE_UTF8, 0,
last_statement_change_count },
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, 0, 0, soundexFunc}, { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif #endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
{ "randstr", 2, 0, 0, 0, randStr }, { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
{ "test_destructor", 1, 0, SQLITE_UTF8, 0, test_destructor},
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
#endif #endif
}; };
static struct { static struct {
@ -980,11 +1025,11 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
case 1: pArg = db; break; case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break; case 2: pArg = (void *)(-1); break;
} }
sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, 0, 0, pArg, sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
0, aAggs[i].xStep, aAggs[i].xFinalize); 0, pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
if( aAggs[i].needCollSeq ){ if( aAggs[i].needCollSeq ){
FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName, FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
strlen(aAggs[i].zName), aAggs[i].nArg, 0, 0); strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0);
if( pFunc && aAggs[i].needCollSeq ){ if( pFunc && aAggs[i].needCollSeq ){
pFunc->needCollSeq = 1; pFunc->needCollSeq = 1;
} }

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.217 2004/06/12 01:43:26 danielk1977 Exp $ ** $Id: main.c,v 1.218 2004/06/12 09:25:15 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -495,10 +495,11 @@ void sqlite3_close(sqlite *db){
} }
} }
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i); CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* sqliteFree(pColl); */ sqliteFree(pColl);
} }
sqlite3HashClear(&db->aCollSeq);
sqlite3HashClear(&db->aFunc); sqlite3HashClear(&db->aFunc);
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
@ -567,7 +568,6 @@ const char *sqlite3ErrStr(int rc){
*/ */
static int sqliteDefaultBusyCallback( static int sqliteDefaultBusyCallback(
void *Timeout, /* Maximum amount of time to wait */ void *Timeout, /* Maximum amount of time to wait */
const char *NotUsed, /* The name of the table that is busy */
int count /* Number of times table has been busy */ int count /* Number of times table has been busy */
){ ){
#if SQLITE_MIN_SLEEP_MS==1 #if SQLITE_MIN_SLEEP_MS==1
@ -678,7 +678,7 @@ int sqlite3_create_function(
sqlite3 *db, sqlite3 *db,
const char *zFunctionName, const char *zFunctionName,
int nArg, int nArg,
int eTextRep, int enc,
int iCollateArg, int iCollateArg,
void *pUserData, void *pUserData,
void (*xFunc)(sqlite3_context*,int,sqlite3_value **), void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
@ -696,8 +696,28 @@ int sqlite3_create_function(
(255<(nName = strlen(zFunctionName))) ){ (255<(nName = strlen(zFunctionName))) ){
return SQLITE_ERROR; return SQLITE_ERROR;
} }
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
**
** If SQLITE_ANY is specified, add three versions of the function
** to the hash table.
*/
if( enc==SQLITE_UTF16 ){
enc = SQLITE_UTF16NATIVE;
}else if( enc==SQLITE_ANY ){
int rc;
rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8,
iCollateArg, pUserData, xFunc, xStep, xFinal);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE,
iCollateArg, pUserData, xFunc, xStep, xFinal);
if( rc!=SQLITE_OK ) return rc;
enc = SQLITE_UTF16BE;
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, eTextRep, 1); p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
if( p==0 ) return 1; if( p==0 ) return 1;
p->xFunc = xFunc; p->xFunc = xFunc;
p->xStep = xStep; p->xStep = xStep;
@ -804,7 +824,7 @@ int sqlite3BtreeFactory(
} }
return sqlite3BtreeOpen(zFilename, ppBtree, nCache, btree_flags, return sqlite3BtreeOpen(zFilename, ppBtree, nCache, btree_flags,
&db->busyHandler); (void *)&db->busyHandler);
} }
/* /*
@ -1182,6 +1202,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
return rc; return rc;
} }
/*
** Register a new collation sequence with the database handle db.
*/
int sqlite3_create_collation( int sqlite3_create_collation(
sqlite3* db, sqlite3* db,
const char *zName, const char *zName,
@ -1191,10 +1214,19 @@ int sqlite3_create_collation(
){ ){
CollSeq *pColl; CollSeq *pColl;
int rc = SQLITE_OK; int rc = SQLITE_OK;
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
*/
if( enc==SQLITE_UTF16 ){
enc = SQLITE_UTF16NATIVE;
}
if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
sqlite3Error(db, SQLITE_ERROR, sqlite3Error(db, SQLITE_ERROR,
"Param 3 to sqlite3_create_collation() must be one of " "Param 3 to sqlite3_create_collation() must be one of "
"SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE" "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
); );
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -1209,6 +1241,9 @@ int sqlite3_create_collation(
return rc; return rc;
} }
/*
** Register a new collation sequence with the database handle db.
*/
int sqlite3_create_collation16( int sqlite3_create_collation16(
sqlite3* db, sqlite3* db,
const char *zName, const char *zName,
@ -1223,6 +1258,10 @@ int sqlite3_create_collation16(
return rc; return rc;
} }
/*
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
int sqlite3_collation_needed( int sqlite3_collation_needed(
sqlite3 *db, sqlite3 *db,
void *pCollNeededArg, void *pCollNeededArg,
@ -1233,6 +1272,11 @@ int sqlite3_collation_needed(
db->pCollNeededArg = pCollNeededArg; db->pCollNeededArg = pCollNeededArg;
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
int sqlite3_collation_needed16( int sqlite3_collation_needed16(
sqlite3 *db, sqlite3 *db,
void *pCollNeededArg, void *pCollNeededArg,

View File

@ -379,8 +379,9 @@ static void md5finalize(sqlite3_context *context){
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, sizeof(*p));
MD5Final(digest,p); MD5Final(digest,p);
DigestToBase16(digest, zBuf); DigestToBase16(digest, zBuf);
sqlite3_result_text(context, zBuf, -1, 1); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
} }
void Md5_Register(sqlite *db){ void Md5_Register(sqlite *db){
sqlite3_create_function(db, "md5sum", -1, 0, 0, 0, 0, md5step, md5finalize); sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, 0,
md5step, md5finalize);
} }

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite. ** to handle SELECT statements in SQLite.
** **
** $Id: select.c,v 1.188 2004/06/11 13:19:21 danielk1977 Exp $ ** $Id: select.c,v 1.189 2004/06/12 09:25:18 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -706,7 +706,7 @@ static void generateColumnNames(
if( p==0 ) continue; if( p==0 ) continue;
if( pEList->a[i].zName ){ if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName; char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, zName, 0); sqlite3VdbeSetColName(v, i, zName, strlen(zName));
continue; continue;
} }
if( p->op==TK_COLUMN && pTabList ){ if( p->op==TK_COLUMN && pTabList ){
@ -725,7 +725,6 @@ static void generateColumnNames(
} }
if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
/* sqlite3VdbeCompressSpace(v, addr); */
}else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
char *zName = 0; char *zName = 0;
char *zTab; char *zTab;

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** presents to client programs.
** **
** @(#) $Id: sqlite.h.in,v 1.100 2004/06/12 01:43:27 danielk1977 Exp $ ** @(#) $Id: sqlite.h.in,v 1.101 2004/06/12 09:25:20 danielk1977 Exp $
*/ */
#ifndef _SQLITE_H_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@ -604,13 +604,13 @@ typedef struct Mem sqlite3_value;
** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted ** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted
** as NULL. ** as NULL.
*/ */
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, int eCopy); int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, long long int); int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);
int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, int eCopy); int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, int eCopy); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
/* /*
@ -833,12 +833,12 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** aggregate takes. If this parameter is negative, then the function or ** aggregate takes. If this parameter is negative, then the function or
** aggregate may take any number of arguments. ** aggregate may take any number of arguments.
** **
** If the fourth parameter is non-zero, this indicates that the function is ** The fourth parameter is one of SQLITE_UTF* values defined below,
** more likely to handle text in UTF-16 encoding than UTF-8. This does not ** indicating the encoding that the function is most likely to handle
** change the behaviour of the programming interface. However, if two ** values in. This does not change the behaviour of the programming
** versions of the same function are registered, one with eTextRep non-zero ** interface. However, if two versions of the same function are registered
** and the other zero, SQLite invokes the version likely to minimize ** with different encoding values, SQLite invokes the version likely to
** conversions between unicode encodings. ** minimize conversions between text encodings.
** **
** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are ** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
** pointers to user implemented C functions that implement the user ** pointers to user implemented C functions that implement the user
@ -897,6 +897,8 @@ int sqlite3_value_int(sqlite3_value*);
long long int sqlite3_value_int64(sqlite3_value*); long long int sqlite3_value_int64(sqlite3_value*);
const unsigned char *sqlite3_value_text(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*);
const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
const void *sqlite3_value_text16be(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*); int sqlite3_value_type(sqlite3_value*);
/* /*
@ -948,19 +950,24 @@ void *sqlite3_user_data(sqlite3_context*);
void *sqlite3_get_auxdata(sqlite3_context*, int); void *sqlite3_get_auxdata(sqlite3_context*, int);
void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*)); void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
#define SQLITE_STATIC ((void(*)(void *))0)
#define SQLITE_TRANSIENT ((void(*)(void *))-1)
/* /*
** User-defined functions invoke the following routines in order to ** User-defined functions invoke the following routines in order to
** set their return value. ** set their return value.
*/ */
void sqlite3_result_blob(sqlite3_context*, const void*, int n, int eCopy); void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_double(sqlite3_context*, double);
void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error(sqlite3_context*, const char*, int);
void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int);
void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int(sqlite3_context*, int);
void sqlite3_result_int64(sqlite3_context*, long long int); void sqlite3_result_int64(sqlite3_context*, long long int);
void sqlite3_result_null(sqlite3_context*); void sqlite3_result_null(sqlite3_context*);
void sqlite3_result_text(sqlite3_context*, const char*, int n, int eCopy); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
void sqlite3_result_value(sqlite3_context*, sqlite3_value*); void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
/* /*

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.284 2004/06/12 01:43:27 danielk1977 Exp $ ** @(#) $Id: sqliteInt.h,v 1.285 2004/06/12 09:25:21 danielk1977 Exp $
*/ */
#include "config.h" #include "config.h"
#include "sqlite3.h" #include "sqlite3.h"
@ -473,7 +473,7 @@ struct sqlite {
struct FuncDef { struct FuncDef {
char *zName; /* SQL name of the function */ char *zName; /* SQL name of the function */
int nArg; /* Number of arguments. -1 means unlimited */ int nArg; /* Number of arguments. -1 means unlimited */
int iPrefEnc; /* Preferred text encoding */ u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
void *pUserData; /* User data parameter */ void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */ FuncDef *pNext; /* Next function with same name */
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
@ -1324,7 +1324,7 @@ ExprList *sqlite3ExprListDup(ExprList*);
SrcList *sqlite3SrcListDup(SrcList*); SrcList *sqlite3SrcListDup(SrcList*);
IdList *sqlite3IdListDup(IdList*); IdList *sqlite3IdListDup(IdList*);
Select *sqlite3SelectDup(Select*); Select *sqlite3SelectDup(Select*);
FuncDef *sqlite3FindFunction(sqlite*,const char*,int,int,int,int); FuncDef *sqlite3FindFunction(sqlite*,const char*,int,int,u8,int);
void sqlite3RegisterBuiltinFunctions(sqlite*); void sqlite3RegisterBuiltinFunctions(sqlite*);
void sqlite3RegisterDateTimeFunctions(sqlite*); void sqlite3RegisterDateTimeFunctions(sqlite*);
int sqlite3SafetyOn(sqlite*); int sqlite3SafetyOn(sqlite*);
@ -1407,6 +1407,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckIndexCollSeq(Parse *, Index *); int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *);
const void *sqlite3ValueText(sqlite3_value*, u8); const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8);

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** A TCL Interface to SQLite
** **
** $Id: tclsqlite.c,v 1.84 2004/06/12 01:43:27 danielk1977 Exp $ ** $Id: tclsqlite.c,v 1.85 2004/06/12 09:25:22 danielk1977 Exp $
*/ */
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@ -277,7 +277,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
if( rc ){ if( rc ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{ }else{
sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1); sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1,
SQLITE_TRANSIENT);
} }
} }
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
@ -784,7 +785,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pFunc->pNext = pDb->pFunc; pFunc->pNext = pDb->pFunc;
pFunc->zScript = (char*)&pFunc[1]; pFunc->zScript = (char*)&pFunc[1];
strcpy(pFunc->zScript, zScript); strcpy(pFunc->zScript, zScript);
sqlite3_create_function(pDb->db, zName, -1, 0, 0, pFunc, tclSqlFunc, 0, 0); sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, 0,
pFunc, tclSqlFunc, 0, 0);
break; break;
} }

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** testing of the SQLite library.
** **
** $Id: test1.c,v 1.75 2004/06/10 14:01:08 danielk1977 Exp $ ** $Id: test1.c,v 1.76 2004/06/12 09:25:23 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@ -341,7 +341,8 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
int i; int i;
for(i=0; i<argc; i++){ for(i=0; i<argc; i++){
if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1, 1); sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1,
SQLITE_TRANSIENT);
break; break;
} }
} }
@ -416,7 +417,7 @@ static void sqlite3ExecFunc(
sqlite3_exec((sqlite*)sqlite3_user_data(context), sqlite3_exec((sqlite*)sqlite3_user_data(context),
sqlite3_value_text(argv[0]), sqlite3_value_text(argv[0]),
execFuncCallback, &x, 0); execFuncCallback, &x, 0);
sqlite3_result_text(context, x.z, x.nUsed, 1); sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
sqliteFree(x.z); sqliteFree(x.z);
} }
@ -449,8 +450,9 @@ static int test_create_function(
return TCL_ERROR; return TCL_ERROR;
} }
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0); sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, 0,
sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db, ifnullFunc, 0, 0);
sqlite3_create_function(db, "x_sqlite3_exec", 1, SQLITE_UTF8, 0, db,
sqlite3ExecFunc, 0, 0); sqlite3ExecFunc, 0, 0);
return TCL_OK; return TCL_OK;
} }
@ -499,8 +501,10 @@ static int test_create_aggregate(
return TCL_ERROR; return TCL_ERROR;
} }
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize); sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, 0,
sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize); countStep,countFinalize);
sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, 0,
countStep,countFinalize);
return TCL_OK; return TCL_OK;
} }
@ -693,7 +697,8 @@ static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}else if( sqlite3StrICmp(zArg0,"int64")==0 ){ }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
sqlite3_result_int64(context, sqlite3_value_int64(argv[1])); sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
}else if( sqlite3StrICmp(zArg0,"string")==0 ){ }else if( sqlite3StrICmp(zArg0,"string")==0 ){
sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1, 1); sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1,
SQLITE_TRANSIENT);
}else if( sqlite3StrICmp(zArg0,"double")==0 ){ }else if( sqlite3StrICmp(zArg0,"double")==0 ){
sqlite3_result_double(context, sqlite3_value_double(argv[1])); sqlite3_result_double(context, sqlite3_value_double(argv[1]));
}else if( sqlite3StrICmp(zArg0,"null")==0 ){ }else if( sqlite3StrICmp(zArg0,"null")==0 ){
@ -735,7 +740,8 @@ static int test_register_func(
return TCL_ERROR; return TCL_ERROR;
} }
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0); rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0,
testFunc, 0, 0);
if( rc!=0 ){ if( rc!=0 ){
Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
return TCL_ERROR; return TCL_ERROR;
@ -845,7 +851,7 @@ static int test_bind(
}else if( strcmp(argv[4],"static")==0 ){ }else if( strcmp(argv[4],"static")==0 ){
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
}else if( strcmp(argv[4],"normal")==0 ){ }else if( strcmp(argv[4],"normal")==0 ){
rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1); rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
}else{ }else{
Tcl_AppendResult(interp, "4th argument should be " Tcl_AppendResult(interp, "4th argument should be "
"\"null\" or \"static\" or \"normal\"", 0); "\"null\" or \"static\" or \"normal\"", 0);
@ -1122,7 +1128,7 @@ static int test_bind_text(
value = Tcl_GetString(objv[3]); value = Tcl_GetString(objv[3]);
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return TCL_ERROR; return TCL_ERROR;
} }
@ -1154,7 +1160,7 @@ static int test_bind_text16(
value = Tcl_GetByteArrayFromObj(objv[3], 0); value = Tcl_GetByteArrayFromObj(objv[3], 0);
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return TCL_ERROR; return TCL_ERROR;
} }
@ -1186,7 +1192,7 @@ static int test_bind_blob(
value = Tcl_GetString(objv[3]); value = Tcl_GetString(objv[3]);
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return TCL_ERROR; return TCL_ERROR;
} }
@ -1892,6 +1898,7 @@ static int test_sqlite3OsUnlock(
return TCL_OK; return TCL_OK;
} }
/* /*
** Register commands with the TCL interpreter. ** Register commands with the TCL interpreter.
*/ */

View File

@ -97,9 +97,12 @@ void sqlite3BeginTrigger(
goto trigger_cleanup; goto trigger_cleanup;
} }
/* Check that no trigger of the specified name exists */ /* Check that the trigger name is not reserved and that no trigger of the
zName = sqliteStrNDup(pName->z, pName->n); ** specified name exists */
sqlite3Dequote(zName); zName = sqlite3TableNameFromToken(pName);
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup;
}
if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){ if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
goto trigger_cleanup; goto trigger_cleanup;

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.367 2004/06/12 01:43:27 danielk1977 Exp $ ** $Id: vdbe.c,v 1.368 2004/06/12 09:25:25 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -73,7 +73,7 @@ int sqlite3_interrupt_count = 0;
** Release the memory associated with the given stack level. This ** Release the memory associated with the given stack level. This
** leaves the Mem.flags field in an inconsistent state. ** leaves the Mem.flags field in an inconsistent state.
*/ */
#define Release(P) if((P)->flags&MEM_Dyn){ sqliteFree((P)->z); } #define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); }
/* /*
** Convert the given stack entity into a string if it isn't one ** Convert the given stack entity into a string if it isn't one
@ -822,6 +822,7 @@ case OP_Variable: {
pTos++; pTos++;
memcpy(pTos, &p->apVar[j], sizeof(*pTos)-NBFS); memcpy(pTos, &p->apVar[j], sizeof(*pTos)-NBFS);
pTos->xDel = 0;
if( pTos->flags&(MEM_Str|MEM_Blob) ){ if( pTos->flags&(MEM_Str|MEM_Blob) ){
pTos->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Short); pTos->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Short);
pTos->flags |= MEM_Static; pTos->flags |= MEM_Static;
@ -912,6 +913,7 @@ case OP_Dup: {
assert( pFrom<=pTos && pFrom>=p->aStack ); assert( pFrom<=pTos && pFrom>=p->aStack );
pTos++; pTos++;
memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS); memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS);
pTos->xDel = 0;
if( pTos->flags & (MEM_Str|MEM_Blob) ){ if( pTos->flags & (MEM_Str|MEM_Blob) ){
if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){ if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){
pTos->flags &= ~MEM_Dyn; pTos->flags &= ~MEM_Dyn;
@ -1120,6 +1122,7 @@ case OP_Concat: {
pTos++; pTos++;
pTos->n = j; pTos->n = j;
pTos->flags = MEM_Str|MEM_Dyn|MEM_Term; pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
pTos->xDel = 0;
pTos->enc = db->enc; pTos->enc = db->enc;
pTos->z = zNew; pTos->z = zNew;
} }
@ -2282,6 +2285,7 @@ case OP_MakeRecord: {
assert( zNewRecord!=(unsigned char *)zTemp ); assert( zNewRecord!=(unsigned char *)zTemp );
pTos->z = zNewRecord; pTos->z = zNewRecord;
pTos->flags = MEM_Blob | MEM_Dyn; pTos->flags = MEM_Blob | MEM_Dyn;
pTos->xDel = 0;
} }
/* If P2 is non-zero, and if the key contains a NULL value, and if this /* If P2 is non-zero, and if the key contains a NULL value, and if this
@ -3308,6 +3312,7 @@ case OP_RowData: {
char *z = sqliteMallocRaw( n ); char *z = sqliteMallocRaw( n );
if( z==0 ) goto no_mem; if( z==0 ) goto no_mem;
pTos->flags = MEM_Blob | MEM_Dyn; pTos->flags = MEM_Blob | MEM_Dyn;
pTos->xDel = 0;
pTos->z = z; pTos->z = z;
} }
if( pC->keyAsData || pOp->opcode==OP_RowKey ){ if( pC->keyAsData || pOp->opcode==OP_RowKey ){
@ -3393,6 +3398,7 @@ case OP_FullKey: {
z = sqliteMallocRaw( amt ); z = sqliteMallocRaw( amt );
if( z==0 ) goto no_mem; if( z==0 ) goto no_mem;
pTos->flags = MEM_Blob | MEM_Dyn; pTos->flags = MEM_Blob | MEM_Dyn;
pTos->xDel = 0;
}else{ }else{
z = pTos->zShort; z = pTos->zShort;
pTos->flags = MEM_Blob | MEM_Short; pTos->flags = MEM_Blob | MEM_Short;
@ -3919,6 +3925,7 @@ case OP_IntegrityCk: {
pTos->z = z; pTos->z = z;
pTos->n = strlen(z); pTos->n = strlen(z);
pTos->flags = MEM_Str | MEM_Dyn | MEM_Term; pTos->flags = MEM_Str | MEM_Dyn | MEM_Term;
pTos->xDel = 0;
} }
pTos->enc = SQLITE_UTF8; pTos->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pTos, db->enc); sqlite3VdbeChangeEncoding(pTos, db->enc);
@ -4163,6 +4170,7 @@ case OP_SortNext: {
pTos->z = pSorter->pData; pTos->z = pSorter->pData;
pTos->n = pSorter->nData; pTos->n = pSorter->nData;
pTos->flags = MEM_Blob|MEM_Dyn|MEM_Term; pTos->flags = MEM_Blob|MEM_Dyn|MEM_Term;
pTos->xDel = 0;
pTos->enc = 0; pTos->enc = 0;
sqliteFree(pSorter->zKey); sqliteFree(pSorter->zKey);
sqliteFree(pSorter); sqliteFree(pSorter);
@ -4252,6 +4260,7 @@ case OP_MemLoad: {
assert( i>=0 && i<p->nMem ); assert( i>=0 && i<p->nMem );
pTos++; pTos++;
memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);; memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);;
pTos->xDel = 0;
if( pTos->flags & (MEM_Str|MEM_Blob) ){ if( pTos->flags & (MEM_Str|MEM_Blob) ){
pTos->flags |= MEM_Ephem; pTos->flags |= MEM_Ephem;
pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
@ -4456,6 +4465,7 @@ case OP_AggGet: {
pTos++; pTos++;
pMem = &pFocus->aMem[i]; pMem = &pFocus->aMem[i];
*pTos = *pMem; *pTos = *pMem;
pTos->xDel = 0;
if( pTos->flags & (MEM_Str|MEM_Blob) ){ if( pTos->flags & (MEM_Str|MEM_Blob) ){
pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
pTos->flags |= MEM_Ephem; pTos->flags |= MEM_Ephem;

View File

@ -136,6 +136,7 @@ struct Mem {
double r; /* Real value */ double r; /* Real value */
char *z; /* String or BLOB value */ char *z; /* String or BLOB value */
char zShort[NBFS]; /* Space for short strings */ char zShort[NBFS]; /* Space for short strings */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
}; };
typedef struct Mem Mem; typedef struct Mem Mem;
@ -373,7 +374,7 @@ int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeChangeEncoding(Mem *, int);
int sqlite3VdbeMemCopy(Mem*, const Mem*); int sqlite3VdbeMemCopy(Mem*, const Mem*);
int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemNulTerminate(Mem*);
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, int); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
void sqlite3VdbeMemSetInt64(Mem*, long long int); void sqlite3VdbeMemSetInt64(Mem*, long long int);
void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetNull(Mem*);
@ -383,6 +384,7 @@ int sqlite3VdbeMemStringify(Mem*, int);
int sqlite3VdbeMemIntegerify(Mem*); int sqlite3VdbeMemIntegerify(Mem*);
int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8); void sqlite3VdbeMemSanity(Mem*, u8);
#endif #endif

View File

@ -63,6 +63,12 @@ const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
const void *sqlite3_value_text16(sqlite3_value* pVal){ const void *sqlite3_value_text16(sqlite3_value* pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
} }
const void *sqlite3_value_text16be(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16BE);
}
const void *sqlite3_value_text16le(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
int sqlite3_value_type(sqlite3_value* pVal){ int sqlite3_value_type(sqlite3_value* pVal){
return pVal->type; return pVal->type;
} }
@ -75,21 +81,21 @@ void sqlite3_result_blob(
sqlite3_context *pCtx, sqlite3_context *pCtx,
const void *z, const void *z,
int n, int n,
int eCopy void (*xDel)(void *)
){ ){
assert( n>0 ); assert( n>0 );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, eCopy); sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
} }
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
sqlite3VdbeMemSetDouble(&pCtx->s, rVal); sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
} }
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
pCtx->isError = 1; pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, 1); sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
} }
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
pCtx->isError = 1; pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, 1); sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
} }
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
@ -104,17 +110,33 @@ void sqlite3_result_text(
sqlite3_context *pCtx, sqlite3_context *pCtx,
const char *z, const char *z,
int n, int n,
int eCopy void (*xDel)(void *)
){ ){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, eCopy); sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
} }
void sqlite3_result_text16( void sqlite3_result_text16(
sqlite3_context *pCtx, sqlite3_context *pCtx,
const void *z, const void *z,
int n, int n,
int eCopy void (*xDel)(void *)
){ ){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, eCopy); sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
}
void sqlite3_result_text16be(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
}
void sqlite3_result_text16le(
sqlite3_context *pCtx,
const void *z,
int n,
void (*xDel)(void *)
){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
} }
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
sqlite3VdbeMemCopy(&pCtx->s, pValue); sqlite3VdbeMemCopy(&pCtx->s, pValue);
@ -404,9 +426,7 @@ static int vdbeUnbind(Vdbe *p, int i){
} }
i--; i--;
pVar = &p->apVar[i]; pVar = &p->apVar[i];
if( pVar->flags&MEM_Dyn ){ sqlite3VdbeMemRelease(pVar);
sqliteFree(pVar->z);
}
pVar->flags = MEM_Null; pVar->flags = MEM_Null;
sqlite3Error(p->db, SQLITE_OK, 0); sqlite3Error(p->db, SQLITE_OK, 0);
return SQLITE_OK; return SQLITE_OK;
@ -420,7 +440,7 @@ int sqlite3_bind_blob(
int i, int i,
const void *zData, const void *zData,
int nData, int nData,
int eCopy void (*xDel)(void*)
){ ){
Vdbe *p = (Vdbe *)pStmt; Vdbe *p = (Vdbe *)pStmt;
Mem *pVar; Mem *pVar;
@ -431,7 +451,7 @@ int sqlite3_bind_blob(
return rc; return rc;
} }
pVar = &p->apVar[i-1]; pVar = &p->apVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, eCopy); rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, xDel);
return rc; return rc;
} }
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
@ -463,7 +483,7 @@ int sqlite3_bind_text(
int i, int i,
const char *zData, const char *zData,
int nData, int nData,
int eCopy void (*xDel)(void*)
){ ){
Vdbe *p = (Vdbe *)pStmt; Vdbe *p = (Vdbe *)pStmt;
Mem *pVar; Mem *pVar;
@ -474,7 +494,7 @@ int sqlite3_bind_text(
return rc; return rc;
} }
pVar = &p->apVar[i-1]; pVar = &p->apVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, eCopy); rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, xDel);
if( rc ){ if( rc ){
return rc; return rc;
} }
@ -486,7 +506,7 @@ int sqlite3_bind_text16(
int i, int i,
const void *zData, const void *zData,
int nData, int nData,
int eCopy void (*xDel)(void*)
){ ){
Vdbe *p = (Vdbe *)pStmt; Vdbe *p = (Vdbe *)pStmt;
Mem *pVar; Mem *pVar;
@ -511,7 +531,7 @@ int sqlite3_bind_text16(
}else{ }else{
txt_enc = SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE; txt_enc = SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE;
} }
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, txt_enc, eCopy); rc = sqlite3VdbeMemSetStr(pVar, zData, nData, txt_enc, xDel);
if( rc ){ if( rc ){
return rc; return rc;
} }

View File

@ -544,9 +544,7 @@ int sqlite3VdbeList(
*/ */
if( p->pTos==&p->aStack[4] ){ if( p->pTos==&p->aStack[4] ){
for(i=0; i<5; i++){ for(i=0; i<5; i++){
if( p->aStack[i].flags & MEM_Dyn ){ sqlite3VdbeMemRelease(&p->aStack[i]);
sqliteFree(p->aStack[i].z);
}
p->aStack[i].flags = 0; p->aStack[i].flags = 0;
} }
} }
@ -700,54 +698,6 @@ void sqlite3VdbeSorterReset(Vdbe *p){
} }
} }
/*
** Reset an Agg structure. Delete all its contents.
**
** For installable aggregate functions, if the step function has been
** called, make sure the finalizer function has also been called. The
** finalizer might need to free memory that was allocated as part of its
** private context. If the finalizer has not been called yet, call it
** now.
*/
#if 0
void sqlite3VdbeAggReset(Agg *pAgg){
int i;
HashElem *p;
for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){
AggElem *pElem = sqliteHashData(p);
assert( pAgg->apFunc!=0 );
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
sqlite3_context ctx;
ctx.pFunc = pAgg->apFunc[i];
ctx.s.flags = MEM_Null;
ctx.pAgg = pMem->z;
ctx.cnt = pMem->i;
ctx.isStep = 0;
ctx.isError = 0;
(*pAgg->apFunc[i]->xFinalize)(&ctx);
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
sqliteFree(pMem->z);
}
if( ctx.s.flags & MEM_Dyn ){
sqliteFree(ctx.s.z);
}
}else if( pMem->flags & MEM_Dyn ){
sqliteFree(pMem->z);
}
}
sqliteFree(pElem);
}
sqlite3HashClear(&pAgg->hash);
sqliteFree(pAgg->apFunc);
pAgg->apFunc = 0;
pAgg->pCurrent = 0;
pAgg->pSearch = 0;
pAgg->nMem = 0;
}
#endif
/* /*
** Reset an Agg structure. Delete all its contents. ** Reset an Agg structure. Delete all its contents.
** **
@ -806,8 +756,8 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
if( pMem->z!=0 && pMem->z!=pMem->z ){ if( pMem->z!=0 && pMem->z!=pMem->z ){
sqliteFree(pMem->z); sqliteFree(pMem->z);
} }
}else if( pMem->flags&MEM_Dyn ){ }else{
sqliteFree(pMem->z); sqlite3VdbeMemRelease(pMem);
} }
} }
sqliteFree(pElem); sqliteFree(pElem);
@ -915,9 +865,7 @@ static void Cleanup(Vdbe *p){
if( p->aStack ){ if( p->aStack ){
Mem *pTos = p->pTos; Mem *pTos = p->pTos;
while( pTos>=p->aStack ){ while( pTos>=p->aStack ){
if( pTos->flags & MEM_Dyn ){ sqlite3VdbeMemRelease(pTos);
sqliteFree(pTos->z);
}
pTos--; pTos--;
} }
p->pTos = pTos; p->pTos = pTos;
@ -925,9 +873,7 @@ static void Cleanup(Vdbe *p){
closeAllCursors(p); closeAllCursors(p);
if( p->aMem ){ if( p->aMem ){
for(i=0; i<p->nMem; i++){ for(i=0; i<p->nMem; i++){
if( p->aMem[i].flags & MEM_Dyn ){ sqlite3VdbeMemRelease(&p->aMem[i]);
sqliteFree(p->aMem[i].z);
}
} }
} }
sqliteFree(p->aMem); sqliteFree(p->aMem);
@ -985,7 +931,10 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
** **
** This call must be made after a call to sqlite3VdbeSetNumCols(). ** This call must be made after a call to sqlite3VdbeSetNumCols().
** **
** Parameter N may be either P3_DYNAMIC or P3_STATIC. ** If N==P3_STATIC it means that zName is a pointer to a constant static
** string and we can just copy the pointer. If it is P3_DYNAMIC, then
** the string is freed using sqliteFree() when the vdbe is finished with
** it. Otherwise, N bytes of zName are copied.
*/ */
int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
int rc; int rc;
@ -1007,13 +956,14 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
} }
pColName = &(p->aColName[idx]); pColName = &(p->aColName[idx]);
if( N==0 ){ if( N==P3_DYNAMIC || N==P3_STATIC ){
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, 1); rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
}else{ }else{
rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8, N>0); rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT);
} }
if( rc==SQLITE_OK && N==P3_DYNAMIC ){ if( rc==SQLITE_OK && N==P3_DYNAMIC ){
pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn; pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
pColName->xDel = 0;
} }
return rc; return rc;
} }
@ -1396,9 +1346,7 @@ void sqlite3VdbeDelete(Vdbe *p){
#endif #endif
} }
for(i=0; i<p->nVar; i++){ for(i=0; i<p->nVar; i++){
if( p->apVar[i].flags&MEM_Dyn ){ sqlite3VdbeMemRelease(&p->apVar[i]);
sqliteFree(p->apVar[i].z);
}
} }
if( p->azColName16 ){ if( p->azColName16 ){
for(i=0; i<p->nResColumn; i++){ for(i=0; i<p->nResColumn; i++){
@ -1678,12 +1626,8 @@ int sqlite3VdbeRecordCompare(
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2); d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0); rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
if( mem1.flags&MEM_Dyn ){ sqlite3VdbeMemRelease(&mem1);
sqliteFree(mem1.z); sqlite3VdbeMemRelease(&mem2);
}
if( mem2.flags&MEM_Dyn ){
sqliteFree(mem2.z);
}
if( rc!=0 ){ if( rc!=0 ){
break; break;
} }
@ -1753,9 +1697,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid); lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v); sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
*rowid = v.i; *rowid = v.i;
if( m.flags & MEM_Dyn ){ sqlite3VdbeMemRelease(&m);
sqliteFree(m.z);
}
return SQLITE_OK; return SQLITE_OK;
} }
@ -1791,8 +1733,6 @@ int sqlite3VdbeIdxKeyCompare(
} }
lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z); lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
*res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey); *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
if( m.flags & MEM_Dyn ){ sqlite3VdbeMemRelease(&m);
sqliteFree(m.z);
}
return SQLITE_OK; return SQLITE_OK;
} }

View File

@ -54,9 +54,8 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
if( pMem->flags&MEM_Dyn ){ sqlite3VdbeMemRelease(pMem);
sqliteFree(pMem->z);
}
/* Result of sqlite3utfTranslate is currently always dynamically /* Result of sqlite3utfTranslate is currently always dynamically
** allocated and nul terminated. This might be altered as a performance ** allocated and nul terminated. This might be altered as a performance
** enhancement later. ** enhancement later.
@ -65,6 +64,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
pMem->n = n; pMem->n = n;
pMem->flags &= ~(MEM_Ephem | MEM_Short | MEM_Static); pMem->flags &= ~(MEM_Ephem | MEM_Short | MEM_Static);
pMem->flags |= MEM_Str | MEM_Dyn | MEM_Term; pMem->flags |= MEM_Str | MEM_Dyn | MEM_Term;
pMem->xDel = 0;
}else{ }else{
/* Must be translating between UTF-16le and UTF-16be. */ /* Must be translating between UTF-16le and UTF-16be. */
int i; int i;
@ -98,6 +98,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
pMem->flags |= MEM_Dyn|MEM_Term; pMem->flags |= MEM_Dyn|MEM_Term;
pMem->xDel = 0;
memcpy(z, pMem->z, n ); memcpy(z, pMem->z, n );
z[n] = 0; z[n] = 0;
z[n+1] = 0; z[n+1] = 0;
@ -129,6 +130,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
pMem->flags |= MEM_Dyn|MEM_Term; pMem->flags |= MEM_Dyn|MEM_Term;
pMem->xDel = 0;
} }
memcpy(z, pMem->z, n ); memcpy(z, pMem->z, n );
z[n] = 0; z[n] = 0;
@ -199,12 +201,19 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
} }
/* /*
** Release any memory held by the Mem ** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and
** (Mem.type==SQLITE_TEXT).
*/ */
static void releaseMem(Mem *p){ void sqlite3VdbeMemRelease(Mem *p){
if( p->flags & MEM_Dyn ){ if( p->flags & MEM_Dyn ){
sqliteFree(p->z); if( p->xDel ){
p->xDel((void *)p->z);
}else{
sqliteFree(p->z);
}
p->z = 0; p->z = 0;
p->xDel = 0;
} }
} }
@ -260,7 +269,7 @@ int sqlite3VdbeMemRealify(Mem *pMem){
** Delete any previous value and set the value stored in *pMem to NULL. ** Delete any previous value and set the value stored in *pMem to NULL.
*/ */
void sqlite3VdbeMemSetNull(Mem *pMem){ void sqlite3VdbeMemSetNull(Mem *pMem){
releaseMem(pMem); sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null; pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL; pMem->type = SQLITE_NULL;
} }
@ -270,7 +279,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
** manifest type INTEGER. ** manifest type INTEGER.
*/ */
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
releaseMem(pMem); sqlite3VdbeMemRelease(pMem);
pMem->i = val; pMem->i = val;
pMem->flags = MEM_Int; pMem->flags = MEM_Int;
pMem->type = SQLITE_INTEGER; pMem->type = SQLITE_INTEGER;
@ -281,7 +290,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
** manifest type REAL. ** manifest type REAL.
*/ */
void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
releaseMem(pMem); sqlite3VdbeMemRelease(pMem);
pMem->r = val; pMem->r = val;
pMem->flags = MEM_Real; pMem->flags = MEM_Real;
pMem->type = SQLITE_FLOAT; pMem->type = SQLITE_FLOAT;
@ -291,8 +300,9 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
** Copy the contents of memory cell pFrom into pTo. ** Copy the contents of memory cell pFrom into pTo.
*/ */
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
releaseMem(pTo); sqlite3VdbeMemRelease(pTo);
memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
pTo->xDel = 0;
if( pTo->flags & (MEM_Str|MEM_Blob) ){ if( pTo->flags & (MEM_Str|MEM_Blob) ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
pTo->flags |= MEM_Ephem; pTo->flags |= MEM_Ephem;
@ -309,9 +319,9 @@ int sqlite3VdbeMemSetStr(
const char *z, /* String pointer */ const char *z, /* String pointer */
int n, /* Bytes in string, or negative */ int n, /* Bytes in string, or negative */
u8 enc, /* Encoding of z. 0 for BLOBs */ u8 enc, /* Encoding of z. 0 for BLOBs */
int eCopy /* True if this function should make a copy of z */ void (*xDel)(void*) /* Destructor function */
){ ){
releaseMem(pMem); sqlite3VdbeMemRelease(pMem);
if( !z ){ if( !z ){
pMem->flags = MEM_Null; pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL; pMem->type = SQLITE_NULL;
@ -319,14 +329,19 @@ int sqlite3VdbeMemSetStr(
} }
pMem->z = (char *)z; pMem->z = (char *)z;
if( eCopy ){ if( xDel==SQLITE_STATIC ){
pMem->flags = MEM_Static;
}else if( xDel==SQLITE_TRANSIENT ){
pMem->flags = MEM_Ephem; pMem->flags = MEM_Ephem;
}else{ }else{
pMem->flags = MEM_Static; pMem->flags = MEM_Dyn;
pMem->xDel = xDel;
} }
pMem->enc = enc; pMem->enc = enc;
pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT; pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
pMem->n = n; pMem->n = n;
switch( enc ){ switch( enc ){
case 0: case 0:
pMem->flags |= MEM_Blob; pMem->flags |= MEM_Blob;
@ -352,7 +367,7 @@ int sqlite3VdbeMemSetStr(
default: default:
assert(0); assert(0);
} }
if( eCopy ){ if( xDel==SQLITE_TRANSIENT ){
return sqlite3VdbeMemMakeWriteable(pMem); return sqlite3VdbeMemMakeWriteable(pMem);
} }
return SQLITE_OK; return SQLITE_OK;
@ -510,6 +525,7 @@ int sqlite3VdbeMemFromBtree(
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
pMem->xDel = 0;
}else{ }else{
zData = &(pMem->zShort[0]); zData = &(pMem->zShort[0]);
pMem->flags = MEM_Blob|MEM_Short|MEM_Term; pMem->flags = MEM_Blob|MEM_Short|MEM_Term;
@ -611,24 +627,7 @@ sqlite3_value* sqlite3ValueNew(){
} }
void sqlite3ValueSetStr(sqlite3_value *v, int n, const void *z, u8 enc){ void sqlite3ValueSetStr(sqlite3_value *v, int n, const void *z, u8 enc){
Mem *p = (Mem *)v; sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, SQLITE_STATIC);
if( p->z && p->flags&MEM_Dyn ){
sqliteFree(p->z);
}
p->z = (char *)z;
p->n = n;
p->enc = enc;
p->type = SQLITE_TEXT;
p->flags = (MEM_Str|MEM_Static);
if( p->n<0 ){
if( enc==SQLITE_UTF8 ){
p->n = strlen(p->z);
}else{
p->n = sqlite3utf16ByteLen(p->z, -1);
}
}
return;
} }
void sqlite3ValueFree(sqlite3_value *v){ void sqlite3ValueFree(sqlite3_value *v){

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing built-in functions. # focus of this file is testing built-in functions.
# #
# $Id: func.test,v 1.20 2004/06/02 00:41:10 drh Exp $ # $Id: func.test,v 1.21 2004/06/12 09:25:30 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -336,4 +336,44 @@ do_test func-11.1 {
} }
} [sqlite -version] } [sqlite -version]
# Test that destructors passed to sqlite by calls to sqlite3_result_text()
# etc. are called.
do_test func-12.1 {
execsql {
SELECT test_destructor('hello world'), test_destructor_count();
}
} {{hello world} 1}
do_test func-12.2 {
execsql {
SELECT test_destructor_count();
}
} {0}
do_test func-12.3 {
execsql {
SELECT test_destructor('hello')||' world', test_destructor_count();
}
} {{hello world} 0}
do_test func-12.4 {
execsql {
SELECT test_destructor_count();
}
} {0}
do_test func-12.5 {
execsql {
CREATE TABLE t4(x);
INSERT INTO t4 VALUES(test_destructor('hello'));
INSERT INTO t4 VALUES(test_destructor('world'));
SELECT min(test_destructor(x)), max(test_destructor(x)) FROM t4;
}
} {hello world}
do_test func-12.6 {
execsql {
SELECT test_destructor_count();
}
} {0}
finish_test finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the CREATE INDEX statement. # focus of this file is testing the CREATE INDEX statement.
# #
# $Id: index.test,v 1.27 2004/05/28 12:33:32 danielk1977 Exp $ # $Id: index.test,v 1.28 2004/06/12 09:25:30 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -220,7 +220,7 @@ do_test index-7.3 {
SELECT name FROM sqlite_master SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='test1' WHERE type='index' AND tbl_name='test1'
} }
} {{(test1 autoindex 1)}} } {sqlite_autoindex_test1_1}
do_test index-7.4 { do_test index-7.4 {
execsql {DROP table test1} execsql {DROP table test1}
execsql {SELECT name FROM sqlite_master WHERE type!='meta'} execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
@ -518,4 +518,89 @@ do_test index-15.2 {
} {8 5 2 1 3 6 11 9 10 4 7} } {8 5 2 1 3 6 11 9 10 4 7}
integrity_check index-15.1 integrity_check index-15.1
# The following tests - index-16.* - test that when a table definition
# includes qualifications that specify the same constraint twice only a
# single index is generated to enforce the constraint.
#
# For example: "CREATE TABLE abc( x PRIMARY KEY, UNIQUE(x) );"
#
do_test index-16.1 {
execsql {
CREATE TABLE t7(c UNIQUE PRIMARY KEY);
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.2 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c UNIQUE PRIMARY KEY);
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.3 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c PRIMARY KEY, UNIQUE(c) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.4 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d , UNIQUE(c, d), PRIMARY KEY(c, d) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.5 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d , UNIQUE(c), PRIMARY KEY(c, d) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {2}
# Test that automatically create indices are named correctly. The current
# convention is: "sqlite_autoindex_<table name>_<integer>"
#
# Then check that it is an error to try to drop any automtically created
# indices.
do_test index-17.1 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d UNIQUE, UNIQUE(c), PRIMARY KEY(c, d) );
SELECT name FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {sqlite_autoindex_t7_1 sqlite_autoindex_t7_2 sqlite_autoindex_t7_3}
do_test index-17.2 {
catchsql {
DROP INDEX sqlite_autoindex_t7_1;
}
} {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}}
# The following tests ensure that it is not possible to explicitly name
# a schema object with a name beginning with "sqlite_". Granted that is a
# little outside the focus of this test scripts, but this has got to be
# tested somewhere.
do_test index-18.1 {
catchsql {
CREATE TABLE sqlite_t1(a, b, c);
}
} {1 {object name reserved for internal use: sqlite_t1}}
do_test index-18.2 {
catchsql {
CREATE INDEX sqlite_i1 ON t7(c);
}
} {1 {object name reserved for internal use: sqlite_i1}}
do_test index-18.3 {
catchsql {
CREATE VIEW sqlite_v1 AS SELECT * FROM t7;
}
} {1 {object name reserved for internal use: sqlite_v1}}
do_test index-18.4 {
catchsql {
CREATE TRIGGER sqlite_tr1 BEFORE INSERT ON t7 BEGIN SELECT 1; END;
}
} {1 {object name reserved for internal use: sqlite_tr1}}
finish_test finish_test

View File

@ -13,7 +13,7 @@
# This file implements tests for the special processing associated # This file implements tests for the special processing associated
# with INTEGER PRIMARY KEY columns. # with INTEGER PRIMARY KEY columns.
# #
# $Id: intpkey.test,v 1.15 2004/05/27 17:22:56 drh Exp $ # $Id: intpkey.test,v 1.16 2004/06/12 09:25:30 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -34,7 +34,7 @@ do_test intpkey-1.1 {
SELECT name FROM sqlite_master SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='t1'; WHERE type='index' AND tbl_name='t1';
} }
} {{(t1 autoindex 1)}} } {sqlite_autoindex_t1_1}
# Now create a table with an integer primary key and verify that # Now create a table with an integer primary key and verify that
# there is no associated index. # there is no associated index.

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the CREATE TABLE statement. # focus of this file is testing the CREATE TABLE statement.
# #
# $Id: table.test,v 1.25 2004/06/07 10:00:31 danielk1977 Exp $ # $Id: table.test,v 1.26 2004/06/12 09:25:30 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -96,13 +96,13 @@ do_test table-2.1 {
do_test table-2.1b { do_test table-2.1b {
set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg]
lappend v $msg lappend v $msg
} {1 {table sqlite_master already exists}} } {1 {object name reserved for internal use: sqlite_master}}
do_test table-2.1c { do_test table-2.1c {
db close db close
sqlite db test.db sqlite db test.db
set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg]
lappend v $msg lappend v $msg
} {1 {table sqlite_master already exists}} } {1 {object name reserved for internal use: sqlite_master}}
do_test table-2.1d { do_test table-2.1d {
execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'} execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'}
} {} } {}