]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
(1) Modifications to the user-function interface and (2) Internal changes
authordanielk1977 <danielk1977@noemail.net>
Sat, 12 Jun 2004 09:25:12 +0000 (09:25 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sat, 12 Jun 2004 09:25:12 +0000 (09:25 +0000)
to automatically created indices. (CVS 1575)

FossilOrigin-Name: 5903f53828b5d282b33e27813417e4317c9ecf0b

23 files changed:
manifest
manifest.uuid
src/build.c
src/date.c
src/expr.c
src/func.c
src/main.c
src/md5.c
src/select.c
src/sqlite.h.in
src/sqliteInt.h
src/tclsqlite.c
src/test1.c
src/trigger.c
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
src/vdbemem.c
test/func.test
test/index.test
test/intpkey.test
test/table.test

index 49ffd7bb57d99ef6a820dcc4c6a8183023f46778..63f5b8342b7b456b5e255abd18f6eac3b309c7e0 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Bug\sfix\sin\sthe\sunix\slocking\scode.\s(CVS\s1574)
-D 2004-06-12T02:17:15
+C (1)\sModifications\sto\sthe\suser-function\sinterface\sand\s(2)\sInternal\schanges\nto\sautomatically\screated\sindices.\s(CVS\s1575)
+D 2004-06-12T09:25:12
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -28,18 +28,18 @@ F src/attach.c 93b8ecec4a8d7b4e9f2479e2327d90c9d01765e8
 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
 F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584
 F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
-F src/build.c 1943d5910d0a9807dd788758c41c5b1900a8da78
-F src/date.c 2d193dbe7ca0d68a81be0ed64fb455b61ceb420d
+F src/build.c 916a84fa5f8bfd44dbe14c3d7c923dd07ee7373f
+F src/date.c 65b483caeb0e4dd663667d2f927caa058168ebff
 F src/delete.c 911221aadb35d610c84fadb32e71c52990827e58
 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
-F src/expr.c 03ab3de3897a89c4b4fce4438566e8fef1d973f7
-F src/func.c a58fef26514e26f49312785d2fde370e3a8a85a4
+F src/expr.c f9eafe34828ebc9040b4f0f4de2c1e6a0aee296b
+F src/func.c 3b86bf207b21c1eff766c06c67a0712e756873e5
 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
 F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
 F src/insert.c 68c7f3ddd6a7f1e5596d6996da1a2861b3789a3a
 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
-F src/main.c 86b0946b5d99d4c42437d50494732a316025d141
-F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
+F src/main.c 9061fff2b04759d849155a334bf2a9f158d325d7
+F src/md5.c d77a389955759c8329bb357e3d71bac3d6eb710b
 F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380
 F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348
 F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0
@@ -54,29 +54,29 @@ F src/parse.y 097438674976355a10cf177bd97326c548820b86
 F src/pragma.c e288bd122d3ca41ec2032475abde1ff5fa3095f4
 F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c d29488f86e61e0d45dff318e1f04ba6a7e5782d0
+F src/select.c 164d1a68b3cc3c6a53ca9632a47ccbf9fde267b8
 F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
-F src/sqlite.h.in a4bee5b5c96d8a19f62c750b370bb05ab9073871
-F src/sqliteInt.h 289523cf5337316d85be9b1bb9a067f1d52f80e5
+F src/sqlite.h.in 36c253844656186ca53e1999efa6ef7b44f88779
+F src/sqliteInt.h 924f0bcb493722c90cec7b19a240a37a4f01bbe7
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
-F src/tclsqlite.c 689e47545c55dd70e537c1048da47555cb7790ea
-F src/test1.c 5f5c0773df1091cc02ddf6608a8f6e0c65940a56
+F src/tclsqlite.c f094cc80cdbc87178c1e28db7749e8770b301554
+F src/test1.c e7588e3e55f7595c76874a4b9c6365e891ac69d1
 F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9
 F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
 F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
 F src/test5.c 13ac1db35b03acbc197ceb245fe862da5ebf2369
 F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
-F src/trigger.c d1a4d7a59b34c811bf6070d64d0497baa0140dcf
+F src/trigger.c 3ff6f24e5273767117126b712eaae24c3d6466aa
 F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38
 F src/utf.c e16737b3fc4201bf7ce9bd8ced5250596aa31b76
 F src/util.c 90375fa253137562d536ccdd40b297f0fd7413fc
 F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
-F src/vdbe.c 230613d7524024c99a30fd67bd16bda0860878fe
+F src/vdbe.c 026b78bc404a2585aaefbf876295ed3ae892d769
 F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
-F src/vdbeInt.h 57b7001bc18de348f2180c5fa8a85b687592a19b
-F src/vdbeapi.c d7803664ea8bacc109ddb4b96ce8c5785ff60138
-F src/vdbeaux.c fefea411bd41ac46fada191d017a414817f7d86b
-F src/vdbemem.c 26cd5419a9c9e7a8959618376f04afdb433b77a3
+F src/vdbeInt.h c4ff480cd8f859c9862d759aebd0fe5ebaef47a1
+F src/vdbeapi.c ee350b552fc4c1c695b760f914f69e9c5556e829
+F src/vdbeaux.c 1d0dbaf73c89bd1cc27abad19ee0aa26ab5d03f4
+F src/vdbemem.c 34f59988831ea032b7f526c2c73175f9f4c0f3ad
 F src/where.c dda77afaa593cd54e5955ec433076de18faf62f6
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
@@ -109,14 +109,14 @@ F test/enc.test a55481d45ff493804e8d88357feb4642fc50a6b2
 F test/enc2.test 1d469f58ee7f187bf06e11bd72a12bdea6362b2f
 F test/expr.test 521588701dae8cf5aa2b8a18c5c897711f754332
 F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7
-F test/func.test 9816fbed0a5e87e00f4fc88b4cdcd638abc524c4
+F test/func.test a63cf7a16bbd9dd1430214f6a0625099faa530f3
 F test/hook.test c4102c672d67f8fb60ea459842805abcba69a747
 F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a
-F test/index.test ad3f479a3dc4a6d9105a2c88e3ee432498441c34
+F test/index.test 4d2e73647872b540df4335387cc91faff4365020
 F test/insert.test 6ec324659656f4a86e4abfcf1a1fd2795ba6b603
 F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
 F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
-F test/intpkey.test e93d739c8a49f5f63748d4ed1c8084c33dc4c0a1
+F test/intpkey.test e6e0d7cca0e64ec09cbf683a4712ed2196073742
 F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4
 F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd
 F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
@@ -151,7 +151,7 @@ F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
 F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
 F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8
 F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
-F test/table.test 1defd90e8200661a822618b18748b9339a7fef2f
+F test/table.test bbae9f267e947963f8951e72516667ab16c5810c
 F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
 F test/tclsqlite.test 2ff5abfd1e133cddcfc61ad5850e3b93f4a7ff40
 F test/temptable.test 6809810546311140f1f4efb4a4fc679b36495f50
@@ -223,7 +223,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248
 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 4f1cfca5ca703d0068cf8d6222dc8e0cfb7e24b6
-R 5ae96fc36d6708ebd2e3e17bdca09c44
-U drh
-Z 179ef88834f751e9c7fc73c1211cbbf2
+P dcad244f58453d23f2bcb749dcea077434bbd08c
+R 5693485a98aab5da11e93316c0299999
+U danielk1977
+Z 4d571fd8206bcad58754dc2ba435cca7
index c63ce054672a295c536b8c7efd1b8b1b133e23d9..7989998683738a55f5049292abcb8d6be75919ba 100644 (file)
@@ -1 +1 @@
-dcad244f58453d23f2bcb749dcea077434bbd08c
\ No newline at end of file
+5903f53828b5d282b33e27813417e4317c9ecf0b
\ No newline at end of file
index 5823b24774fbea9c54106b606659a410337d86af..0af83089a8f101a132aeb93ea7bd8d9633da963b 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     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 <ctype.h>
@@ -479,6 +479,21 @@ int sqlite3TwoPartName(
   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
 ** the first of several action routines that get called in response
@@ -541,6 +556,9 @@ void sqlite3StartTable(
 
   pParse->sNameToken = *pName;
   zName = sqlite3TableNameFromToken(pName);
+  if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+    return;
+  }
   if( zName==0 ) return;
   if( db->init.iDb==1 ) isTemp = 1;
 #ifndef SQLITE_OMIT_AUTHORIZATION
@@ -1854,7 +1872,7 @@ void sqlite3CreateIndex(
   Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
 ){
   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;
   int i, j;
   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
   ** own name.
   */
-  if( pName && !db->init.busy ){
-    Index *pISameName;    /* Another index with the same name */
-    Table *pTSameName;    /* A table with same name as the index */
-    zName = sqliteStrNDup(pName->z, pName->n);
+  if( pName ){
+    zName = sqlite3TableNameFromToken(pName);
     if( zName==0 ) goto exit_create_index;
-    if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
-      sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+    if( SQLITE_OK!=sqlite3CheckObjectName(pParse, 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;
+    if( !db->init.busy ){
+      Index *pISameName;    /* Another index with the same name */
+      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 ){
     char zBuf[30];
     int n;
     Index *pLoop;
     for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
-    sprintf(zBuf,"%d)",n);
+    sprintf(zBuf,"_%d",n);
     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;
-  }else{
-    zName = sqliteStrNDup(pName->z, pName->n);
   }
 
   /* Check for authorization to create an index.
@@ -2006,7 +2027,6 @@ void sqlite3CreateIndex(
     if( j>=pTab->nCol ){
       sqlite3ErrorMsg(pParse, "table %s has no column named %s",
         pTab->zName, pList->a[i].zName);
-      sqliteFree(pIndex);
       goto exit_create_index;
     }
     pIndex->aiColumn[i] = j;
@@ -2025,6 +2045,46 @@ void sqlite3CreateIndex(
   }
   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
   ** in-memory database structures. 
   */
@@ -2034,30 +2094,11 @@ void sqlite3CreateIndex(
                          pIndex->zName, strlen(pIndex->zName)+1, pIndex);
     if( p ){
       assert( p==pIndex );  /* Malloc must have failed */
-      sqliteFree(pIndex);
       goto exit_create_index;
     }
     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
   ** "sqlite_master" table on the disk.  So do not write to the disk
   ** 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 */
 exit_create_index:
+  if( pIndex ) sqliteFree(pIndex);
   sqlite3ExprListDelete(pList);
   /* sqlite3SrcListDelete(pTable); */
   sqliteFree(zName);
index 51ffb3410d7a82cc9d3a07300353ed1d6b58bba4..e2c502bc18205cf8fa73d0f8123bb6032a27e07d 100644 (file)
@@ -16,7 +16,7 @@
 ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
 ** 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:
 **
@@ -692,7 +692,7 @@ static void datetimeFunc(
     computeYMD_HMS(&x);
     sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
            (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];
     computeHMS(&x);
     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];
     computeYMD(&x);
     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;
-  sqlite3_result_text(context, z, -1, 1);
+  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
   if( z!=zBuf ){
     sqliteFree(z);
   }
@@ -885,7 +885,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite *db){
   int i;
 
   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
-    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, 0, 0, 0,
-        aFuncs[i].xFunc, 0, 0);
+    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
+        SQLITE_UTF8, 0, 0, aFuncs[i].xFunc, 0, 0);
   }
 }
index 4c80f4400f6a97d1e822b44e2cb89be3a3d97d75..45401649abe4c5476cd5f794b84b3cf644d2262a 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** 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 <ctype.h>
@@ -1012,12 +1012,12 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
       int nId;                    /* Number of characters in function name */
       const char *zId;            /* The function name. */
       FuncDef *pDef;
-      int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1;
+      int enc = pParse->db->enc;
 
       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 ){
-        pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, iPrefEnc, 0);
+        pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
         if( pDef==0 ){
           no_such_func = 1;
         }else{
@@ -1280,10 +1280,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
       const char *zId;
       int p2 = 0;
       int i;
-      int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1;
+      u8 enc = pParse->db->enc;
       CollSeq *pColl = 0;
       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 );
       nExpr = sqlite3ExprCodeExprList(pParse, pList);
       for(i=0; i<nExpr && i<32; i++){
@@ -1296,7 +1296,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
       }
       if( pDef->needCollSeq ){
         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);
       break;
@@ -1724,14 +1724,14 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
         }
       }
       if( i>=pParse->nAgg ){
-        int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1;
+        u8 enc = pParse->db->enc;
         i = appendAggInfo(pParse);
         if( i<0 ) return 1;
         pParse->aAgg[i].isAgg = 1;
         pParse->aAgg[i].pExpr = pExpr;
         pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
              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;
       break;
@@ -1781,53 +1781,68 @@ FuncDef *sqlite3FindFunction(
   const char *zName, /* Name of the function.  Not null-terminated */
   int nName,         /* Number of characters in the name */
   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 */
 ){
   FuncDef *p;         /* Iterator variable */
   FuncDef *pFirst;    /* First function with this name */
   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;
 
   pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
   for(p=pFirst; p; p=p->pNext){
-    if( 1 || p->xFunc || p->xStep ){
-      if( p->nArg==nArg && p->iPrefEnc==eTextRep ){
-        /* A perfect match. */
-        pBest = p;
-        matchqual = 4;
-        break;
+    /* During the search for the best function definition, bestmatch is set
+    ** as follows to indicate the quality of the match with the definition
+    ** pointed to by pBest:
+    **
+    ** 0: pBest is NULL. No match has been found.
+    ** 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 ){
-        /* Number of arguments matches, but not the text encoding */
-        pBest = p;
-        matchqual = 3;
+      if( enc==p->iPrefEnc ){
+        match += 2;
       }
-      else if( (p->nArg<0) || (nArg<0) ){
-        if( matchqual<2 && p->iPrefEnc==eTextRep ){
-          /* Matched a varargs function with correct text encoding */
-          pBest = p;
-          matchqual = 2;
-        }
-        if( matchqual<1 ){
-          /* Matched a varargs function with incorrect text encoding */
-          pBest = p;
-          matchqual = 1;
-        }
+      else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
+               (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
+        match += 1;
+      }
+
+      if( match>bestmatch ){
+        pBest = p;
+        bestmatch = match;
       }
     }
   }
 
-  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->nArg = nArg;
     pBest->pNext = pFirst;
     pBest->zName = (char*)&pBest[1];
-    pBest->iPrefEnc = eTextRep;
+    pBest->iPrefEnc = enc;
     memcpy(pBest->zName, zName, nName);
     pBest->zName[nName] = 0;
     sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest);
index 394f7f173e63601f74158581432b6b32690408c1..534486e493af8ee6707608ef6c87024eef7a665d 100644 (file)
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** 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 <math.h>
@@ -75,7 +75,7 @@ static void typeofFunc(
     case SQLITE_FLOAT:   z = "real";    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++; }
   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;
   r = sqlite3_value_double(argv[0]);
   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++){
     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);
 }
 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++){
     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);
 }
 
@@ -586,7 +586,7 @@ static void versionFunc(
   int argc,
   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;
   switch( sqlite3_value_type(argv[0]) ){
     case SQLITE_NULL: {
-      sqlite3_result_text(context, "NULL", 4, 0);
+      sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
       break;
     }
     case SQLITE_INTEGER:
@@ -634,7 +634,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
         zText[(nBlob*2)+3] = '\0';
         zText[0] = 'X';
         zText[1] = '\'';
-        sqlite3_result_text(context, zText, -1, 1);
+        sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
         sqliteFree(zText);
       }
       break;
@@ -656,7 +656,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
       }
       z[j++] = '\'';
       z[j] = 0;
-      sqlite3_result_text(context, z, j, 1);
+      sqlite3_result_text(context, z, j, SQLITE_TRANSIENT);
       sqliteFree(z);
     }
   }
@@ -695,9 +695,9 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
       zResult[j++] = '0';
     }
     zResult[j] = 0;
-    sqlite3_result_text(context, zResult, 4, 1);
+    sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT);
   }else{
-    sqlite3_result_text(context, "?000", 4, 0);
+    sqlite3_result_text(context, "?000", 4, SQLITE_STATIC);
   }
 }
 #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[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
 
@@ -905,37 +947,40 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
      u8 needCollSeq;
      void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
   } aFuncs[] = {
-    { "min",                        -1, 0, 0, 1, minmaxFunc },
-    { "min",                         0, 0, 0, 1, 0          },
-    { "max",                        -1, 2, 0, 1, minmaxFunc },
-    { "max",                         0, 2, 0, 1, 0          },
-    { "typeof",                      1, 0, 0, 0, typeofFunc },
-    { "length",                      1, 0, 0, 0, lengthFunc },
-    { "substr",                      3, 0, 0, 0, substrFunc },
-    { "abs",                         1, 0, 0, 0, absFunc    },
-    { "round",                       1, 0, 0, 0, roundFunc  },
-    { "round",                       2, 0, 0, 0, roundFunc  },
-    { "upper",                       1, 0, 0, 0, upperFunc  },
-    { "lower",                       1, 0, 0, 0, lowerFunc  },
-    { "coalesce",                   -1, 0, 0, 0, ifnullFunc },
-    { "coalesce",                    0, 0, 0, 0, 0          },
-    { "coalesce",                    1, 0, 0, 0, 0          },
-    { "ifnull",                      2, 0, 0, 1, ifnullFunc },
-    { "random",                     -1, 0, 0, 0, randomFunc },
-    { "like",                        2, 0, 0, 0, likeFunc   }, /* UTF-8 */
-    { "like",                        2, 2, 1, 0, likeFunc   }, /* UTF-16 */
-    { "glob",                        2, 0, 0, 0, globFunc   },
-    { "nullif",                      2, 0, 0, 0, nullifFunc },
-    { "sqlite_version",              0, 0, 0, 0, versionFunc},
-    { "quote",                       1, 0, 0, 0, quoteFunc  },
-    { "last_insert_rowid",           0, 1, 0, 0, last_insert_rowid },
-    { "change_count",                0, 1, 0, 0, change_count      },
-    { "last_statement_change_count", 0, 1, 0, 0, last_statement_change_count },
+    { "min",                        -1, 0, SQLITE_UTF8, 1, minmaxFunc },
+    { "min",                         0, 0, SQLITE_UTF8, 1, 0          },
+    { "max",                        -1, 2, SQLITE_UTF8, 1, minmaxFunc },
+    { "max",                         0, 2, SQLITE_UTF8, 1, 0          },
+    { "typeof",                      1, 0, SQLITE_UTF8, 0, typeofFunc },
+    { "length",                      1, 0, SQLITE_UTF8, 0, lengthFunc },
+    { "substr",                      3, 0, SQLITE_UTF8, 0, substrFunc },
+    { "abs",                         1, 0, SQLITE_UTF8, 0, absFunc    },
+    { "round",                       1, 0, SQLITE_UTF8, 0, roundFunc  },
+    { "round",                       2, 0, SQLITE_UTF8, 0, roundFunc  },
+    { "upper",                       1, 0, SQLITE_UTF8, 0, upperFunc  },
+    { "lower",                       1, 0, SQLITE_UTF8, 0, lowerFunc  },
+    { "coalesce",                   -1, 0, SQLITE_UTF8, 0, ifnullFunc },
+    { "coalesce",                    0, 0, SQLITE_UTF8, 0, 0          },
+    { "coalesce",                    1, 0, SQLITE_UTF8, 0, 0          },
+    { "ifnull",                      2, 0, SQLITE_UTF8, 1, ifnullFunc },
+    { "random",                     -1, 0, SQLITE_UTF8, 0, randomFunc },
+    { "like",                        2, 0, SQLITE_UTF8, 0, likeFunc   },
+    { "like",                        2, 2, SQLITE_UTF16,0, likeFunc   },
+    { "glob",                        2, 0, SQLITE_UTF8, 0, globFunc   },
+    { "nullif",                      2, 0, SQLITE_UTF8, 0, nullifFunc },
+    { "sqlite_version",              0, 0, SQLITE_UTF8, 0, versionFunc},
+    { "quote",                       1, 0, SQLITE_UTF8, 0, quoteFunc  },
+    { "last_insert_rowid",           0, 1, SQLITE_UTF8, 0, last_insert_rowid },
+    { "change_count",                0, 1, SQLITE_UTF8, 0, change_count      },
+    { "last_statement_change_count", 0, 1, SQLITE_UTF8, 0, 
+       last_statement_change_count },
 #ifdef SQLITE_SOUNDEX
-    { "soundex",                     1, 0, 0, 0, soundexFunc},
+    { "soundex",                     1, 0, SQLITE_UTF8, 0, soundexFunc},
 #endif
 #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
   };
   static struct {
@@ -980,11 +1025,11 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
       case 1: pArg = db; break;
       case 2: pArg = (void *)(-1); break;
     }
-    sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, 0, 0, pArg,
-        0, aAggs[i].xStep, aAggs[i].xFinalize);
+    sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, 
+        0, pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
     if( aAggs[i].needCollSeq ){
       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 ){
         pFunc->needCollSeq = 1;
       }
index f031de50e3e6f0f6d72d0bcd12baaa010eb47f1e..712d997f919e24c9285ac890e261e541e5a80d45 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** 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 "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);
-    /* sqliteFree(pColl); */
+    sqliteFree(pColl);
   }
+  sqlite3HashClear(&db->aCollSeq);
 
   sqlite3HashClear(&db->aFunc);
   sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
@@ -567,7 +568,6 @@ const char *sqlite3ErrStr(int rc){
 */
 static int sqliteDefaultBusyCallback(
  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 */
 ){
 #if SQLITE_MIN_SLEEP_MS==1
@@ -678,7 +678,7 @@ int sqlite3_create_function(
   sqlite3 *db,
   const char *zFunctionName,
   int nArg,
-  int eTextRep,
+  int enc,
   int iCollateArg,
   void *pUserData,
   void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
@@ -696,8 +696,28 @@ int sqlite3_create_function(
       (255<(nName = strlen(zFunctionName))) ){
     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;
   p->xFunc = xFunc;
   p->xStep = xStep;
@@ -804,7 +824,7 @@ int sqlite3BtreeFactory(
   }
 
   return sqlite3BtreeOpen(zFilename, ppBtree, nCache, btree_flags,
-      &db->busyHandler);
+      (void *)&db->busyHandler);
 }
 
 /*
@@ -1182,6 +1202,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
   return rc;
 }
 
+/*
+** Register a new collation sequence with the database handle db.
+*/
 int sqlite3_create_collation(
   sqlite3* db, 
   const char *zName, 
@@ -1191,10 +1214,19 @@ int sqlite3_create_collation(
 ){
   CollSeq *pColl;
   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 ){
     sqlite3Error(db, SQLITE_ERROR, 
         "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;
   }
@@ -1209,6 +1241,9 @@ int sqlite3_create_collation(
   return rc;
 }
 
+/*
+** Register a new collation sequence with the database handle db.
+*/
 int sqlite3_create_collation16(
   sqlite3* db, 
   const char *zName, 
@@ -1223,6 +1258,10 @@ int sqlite3_create_collation16(
   return rc;
 }
 
+/*
+** Register a collation sequence factory callback with the database handle
+** db. Replace any previously installed collation sequence factory.
+*/
 int sqlite3_collation_needed(
   sqlite3 *db, 
   void *pCollNeededArg, 
@@ -1233,6 +1272,11 @@ int sqlite3_collation_needed(
   db->pCollNeededArg = pCollNeededArg;
   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(
   sqlite3 *db, 
   void *pCollNeededArg, 
index 72f9ef492281d703ad7f0ff34fbd9802f5d1f5b6..91d1051c82e46afeff9d941c0e56bfdf705de10a 100644 (file)
--- a/src/md5.c
+++ b/src/md5.c
@@ -379,8 +379,9 @@ static void md5finalize(sqlite3_context *context){
   p = sqlite3_aggregate_context(context, sizeof(*p));
   MD5Final(digest,p);
   DigestToBase16(digest, zBuf);
-  sqlite3_result_text(context, zBuf, -1, 1);
+  sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
 }
 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);
 }
index b0e54208b7ce6bc334986723f8d0260c16155191..7538b9726a60c1bca10b9c1f899cbdd845564883 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** 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"
 
@@ -706,7 +706,7 @@ static void generateColumnNames(
     if( p==0 ) continue;
     if( pEList->a[i].zName ){
       char *zName = pEList->a[i].zName;
-      sqlite3VdbeSetColName(v, i, zName, 0);
+      sqlite3VdbeSetColName(v, i, zName, strlen(zName));
       continue;
     }
     if( p->op==TK_COLUMN && pTabList ){
@@ -725,7 +725,6 @@ static void generateColumnNames(
       }
       if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
         sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
-        /* sqlite3VdbeCompressSpace(v, addr); */
       }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
         char *zName = 0;
         char *zTab;
index 9c0eec4a3897ab812facc0ef389243d90dfe0a74..a91aac9722b929f1196d4477ef8717a6eb55b428 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** 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_
 #define _SQLITE_H_
@@ -604,13 +604,13 @@ typedef struct Mem sqlite3_value;
 ** an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
 ** 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_int(sqlite3_stmt*, int, int);
 int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);
 int sqlite3_bind_null(sqlite3_stmt*, int);
-int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, int eCopy);
-int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, 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, void(*)(void*));
 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 may take any number of arguments.
 **
-** If the fourth parameter is non-zero, this indicates that the function is
-** more likely to handle text in UTF-16 encoding than UTF-8. This does not
-** change the behaviour of the programming interface. However, if two
-** versions of the same function are registered, one with eTextRep non-zero
-** and the other zero, SQLite invokes the version likely to minimize
-** conversions between unicode encodings.
+** The fourth parameter is one of SQLITE_UTF* values defined below,
+** indicating the encoding that the function is most likely to handle
+** values in.  This does not change the behaviour of the programming
+** interface. However, if two versions of the same function are registered
+** with different encoding values, SQLite invokes the version likely to
+** minimize conversions between text encodings.
 **
 ** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
 ** 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*);
 const unsigned char *sqlite3_value_text(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*);
 
 /*
@@ -948,19 +950,24 @@ void *sqlite3_user_data(sqlite3_context*);
 void *sqlite3_get_auxdata(sqlite3_context*, int);
 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
 ** 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_error(sqlite3_context*, const char*, int);
 void sqlite3_result_error16(sqlite3_context*, const void*, int);
 void sqlite3_result_int(sqlite3_context*, int);
 void sqlite3_result_int64(sqlite3_context*, long long int);
 void sqlite3_result_null(sqlite3_context*);
-void sqlite3_result_text(sqlite3_context*, const char*, int n, int eCopy);
-void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy);
+void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+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*);
 
 /*
index e69fe565112670b1125e4dcfc27f6dd92abede5c..554e3c68e10dbeeadb793d74213e02a5dcf68ca3 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** 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 "sqlite3.h"
@@ -473,7 +473,7 @@ struct sqlite {
 struct FuncDef {
   char *zName;         /* SQL name of the function */
   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 */
   FuncDef *pNext;      /* Next function with same name */
   void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
@@ -1324,7 +1324,7 @@ ExprList *sqlite3ExprListDup(ExprList*);
 SrcList *sqlite3SrcListDup(SrcList*);
 IdList *sqlite3IdListDup(IdList*);
 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 sqlite3RegisterDateTimeFunctions(sqlite*);
 int sqlite3SafetyOn(sqlite*);
@@ -1407,6 +1407,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
 CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
 int sqlite3CheckCollSeq(Parse *, CollSeq *);
 int sqlite3CheckIndexCollSeq(Parse *, Index *);
+int sqlite3CheckObjectName(Parse *, const char *);
 
 const void *sqlite3ValueText(sqlite3_value*, u8);
 int sqlite3ValueBytes(sqlite3_value*, u8);
index c0b751a603da1067759859b091ec4133b594ac4f..03edc162a12ac0ebd3ef6ccdbd27dfa11b69c188 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** 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 */
 
@@ -277,7 +277,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
   if( rc ){
     sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 
   }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
@@ -784,7 +785,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     pFunc->pNext = pDb->pFunc;
     pFunc->zScript = (char*)&pFunc[1];
     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;
   }
 
index 39a3f537781caa6ef0db6bd09a792fc01dbf161f..7ec93709501d597432873e247221f15d3fb1487e 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** 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 "tcl.h"
@@ -341,7 +341,8 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
   int i;
   for(i=0; i<argc; 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;
     }
   }
@@ -416,7 +417,7 @@ static void sqlite3ExecFunc(
   sqlite3_exec((sqlite*)sqlite3_user_data(context),
       sqlite3_value_text(argv[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);
 }
 
@@ -449,8 +450,9 @@ static int test_create_function(
     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_sqlite3_exec", 1, 0, 0, db,
+  sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, 0, 
+      ifnullFunc, 0, 0);
+  sqlite3_create_function(db, "x_sqlite3_exec", 1, SQLITE_UTF8, 0, db,
       sqlite3ExecFunc, 0, 0);
   return TCL_OK;
 }
@@ -499,8 +501,10 @@ static int test_create_aggregate(
     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", 1, 0, 0, 0, 0,countStep,countFinalize);
+  sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, 0,
+      countStep,countFinalize);
+  sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, 0,
+      countStep,countFinalize);
   return TCL_OK;
 }
 
@@ -693,7 +697,8 @@ static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
       }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 ){
         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
@@ -735,7 +740,8 @@ static int test_register_func(
     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 ){
     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
     return TCL_ERROR;
@@ -845,7 +851,7 @@ static int test_bind(
   }else if( strcmp(argv[4],"static")==0 ){
     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 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{
     Tcl_AppendResult(interp, "4th argument should be "
         "\"null\" or \"static\" or \"normal\"", 0);
@@ -1122,7 +1128,7 @@ static int test_bind_text(
   value = Tcl_GetString(objv[3]);
   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 ){
     return TCL_ERROR;
   }
@@ -1154,7 +1160,7 @@ static int test_bind_text16(
   value = Tcl_GetByteArrayFromObj(objv[3], 0);
   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 ){
     return TCL_ERROR;
   }
@@ -1186,7 +1192,7 @@ static int test_bind_blob(
   value = Tcl_GetString(objv[3]);
   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 ){
     return TCL_ERROR;
   }
@@ -1892,6 +1898,7 @@ static int test_sqlite3OsUnlock(
   return TCL_OK;
 }
 
+
 /*
 ** Register commands with the TCL interpreter.
 */
index a842d9b0a4b9229709d18700679b6c449241ddb9..86f0664cf8722ba0afb32dfe3120b6b37a55eb23 100644 (file)
@@ -97,9 +97,12 @@ void sqlite3BeginTrigger(
     goto trigger_cleanup;
   }
 
-  /* Check that no trigger of the specified name exists */
-  zName = sqliteStrNDup(pName->z, pName->n);
-  sqlite3Dequote(zName);
+  /* Check that the trigger name is not reserved and that no trigger of the
+  ** specified name exists */
+  zName = sqlite3TableNameFromToken(pName);
+  if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+    goto trigger_cleanup;
+  }
   if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
     sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
     goto trigger_cleanup;
index 3736ebbf90b41345696b12218eab0921d930d410..fc2d9cff8779ab47392f63d4221529c302107c86 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** 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 "os.h"
@@ -73,7 +73,7 @@ int sqlite3_interrupt_count = 0;
 ** Release the memory associated with the given stack level.  This
 ** 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
@@ -822,6 +822,7 @@ case OP_Variable: {
 
   pTos++;
   memcpy(pTos, &p->apVar[j], sizeof(*pTos)-NBFS);
+  pTos->xDel = 0;
   if( pTos->flags&(MEM_Str|MEM_Blob) ){
     pTos->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Short);
     pTos->flags |= MEM_Static;
@@ -912,6 +913,7 @@ case OP_Dup: {
   assert( pFrom<=pTos && pFrom>=p->aStack );
   pTos++;
   memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS);
+  pTos->xDel = 0;
   if( pTos->flags & (MEM_Str|MEM_Blob) ){
     if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){
       pTos->flags &= ~MEM_Dyn;
@@ -1120,6 +1122,7 @@ case OP_Concat: {
     pTos++;
     pTos->n = j;
     pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
+    pTos->xDel = 0;
     pTos->enc = db->enc;
     pTos->z = zNew;
   }
@@ -2282,6 +2285,7 @@ case OP_MakeRecord: {
     assert( zNewRecord!=(unsigned char *)zTemp );
     pTos->z = zNewRecord;
     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
@@ -3308,6 +3312,7 @@ case OP_RowData: {
       char *z = sqliteMallocRaw( n );
       if( z==0 ) goto no_mem;
       pTos->flags = MEM_Blob | MEM_Dyn;
+      pTos->xDel = 0;
       pTos->z = z;
     }
     if( pC->keyAsData || pOp->opcode==OP_RowKey ){
@@ -3393,6 +3398,7 @@ case OP_FullKey: {
       z = sqliteMallocRaw( amt );
       if( z==0 ) goto no_mem;
       pTos->flags = MEM_Blob | MEM_Dyn;
+      pTos->xDel = 0;
     }else{
       z = pTos->zShort;
       pTos->flags = MEM_Blob | MEM_Short;
@@ -3919,6 +3925,7 @@ case OP_IntegrityCk: {
     pTos->z = z;
     pTos->n = strlen(z);
     pTos->flags = MEM_Str | MEM_Dyn | MEM_Term;
+    pTos->xDel = 0;
   }
   pTos->enc = SQLITE_UTF8;
   sqlite3VdbeChangeEncoding(pTos, db->enc);
@@ -4163,6 +4170,7 @@ case OP_SortNext: {
     pTos->z = pSorter->pData;
     pTos->n = pSorter->nData;
     pTos->flags = MEM_Blob|MEM_Dyn|MEM_Term;
+    pTos->xDel = 0;
     pTos->enc = 0;
     sqliteFree(pSorter->zKey);
     sqliteFree(pSorter);
@@ -4252,6 +4260,7 @@ case OP_MemLoad: {
   assert( i>=0 && i<p->nMem );
   pTos++;
   memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);;
+  pTos->xDel = 0;
   if( pTos->flags & (MEM_Str|MEM_Blob) ){
     pTos->flags |= MEM_Ephem;
     pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
@@ -4456,6 +4465,7 @@ case OP_AggGet: {
   pTos++;
   pMem = &pFocus->aMem[i];
   *pTos = *pMem;
+  pTos->xDel = 0;
   if( pTos->flags & (MEM_Str|MEM_Blob) ){
     pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
     pTos->flags |= MEM_Ephem;
index 8099747518915d5f7c81cd5bdfa3b992a0183107..709287d92e299d7744b68e50c90acde397ef7b41 100644 (file)
@@ -136,6 +136,7 @@ struct Mem {
   double r;           /* Real value */
   char *z;            /* String or BLOB value */
   char zShort[NBFS];  /* Space for short strings */
+  void (*xDel)(void *);  /* If not null, call this function to delete Mem.z */
 };
 typedef struct Mem Mem;
 
@@ -373,7 +374,7 @@ int sqlite3VdbeList(Vdbe*);
 int sqlite3VdbeChangeEncoding(Mem *, int);
 int sqlite3VdbeMemCopy(Mem*, const 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 sqlite3VdbeMemSetDouble(Mem*, double);
 void sqlite3VdbeMemSetNull(Mem*);
@@ -383,6 +384,7 @@ int sqlite3VdbeMemStringify(Mem*, int);
 int sqlite3VdbeMemIntegerify(Mem*);
 int sqlite3VdbeMemRealify(Mem*);
 int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
+void sqlite3VdbeMemRelease(Mem *p);
 #ifndef NDEBUG
 void sqlite3VdbeMemSanity(Mem*, u8);
 #endif
index a3fc2f03f8fbb2d2b41ca7255f00bb514172b8a0..dff0a10ad41ba66744ac33c8db9931dc7bdb47c9 100644 (file)
@@ -63,6 +63,12 @@ const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
 const void *sqlite3_value_text16(sqlite3_value* pVal){
   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){
   return pVal->type;
 }
@@ -75,21 +81,21 @@ void sqlite3_result_blob(
   sqlite3_context *pCtx, 
   const void *z, 
   int n, 
-  int eCopy
+  void (*xDel)(void *)
 ){
   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){
   sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
 }
 void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
   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){
   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){
   sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
@@ -104,17 +110,33 @@ void sqlite3_result_text(
   sqlite3_context *pCtx, 
   const char *z, 
   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(
   sqlite3_context *pCtx, 
   const void *z, 
   int n, 
-  int eCopy
+  void (*xDel)(void *)
+){
+  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_UTF16NATIVE, eCopy);
+  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){
   sqlite3VdbeMemCopy(&pCtx->s, pValue);
@@ -404,9 +426,7 @@ static int vdbeUnbind(Vdbe *p, int i){
   }
   i--;
   pVar = &p->apVar[i];
-  if( pVar->flags&MEM_Dyn ){
-    sqliteFree(pVar->z);
-  }
+  sqlite3VdbeMemRelease(pVar);
   pVar->flags = MEM_Null;
   sqlite3Error(p->db, SQLITE_OK, 0);
   return SQLITE_OK;
@@ -420,7 +440,7 @@ int sqlite3_bind_blob(
   int i, 
   const void *zData, 
   int nData, 
-  int eCopy
+  void (*xDel)(void*)
 ){
   Vdbe *p = (Vdbe *)pStmt;
   Mem *pVar;
@@ -431,7 +451,7 @@ int sqlite3_bind_blob(
     return rc;
   }
   pVar = &p->apVar[i-1];
-  rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, eCopy);
+  rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, xDel);
   return rc;
 }
 int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
@@ -463,7 +483,7 @@ int sqlite3_bind_text(
   int i, 
   const char *zData, 
   int nData, 
-  int eCopy
+  void (*xDel)(void*)
 ){
   Vdbe *p = (Vdbe *)pStmt;
   Mem *pVar;
@@ -474,7 +494,7 @@ int sqlite3_bind_text(
     return rc;
   }
   pVar = &p->apVar[i-1];
-  rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, eCopy);
+  rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, xDel);
   if( rc ){
     return rc;
   }
@@ -486,7 +506,7 @@ int sqlite3_bind_text16(
   int i, 
   const void *zData, 
   int nData, 
-  int eCopy
+  void (*xDel)(void*)
 ){
   Vdbe *p = (Vdbe *)pStmt;
   Mem *pVar;
@@ -511,7 +531,7 @@ int sqlite3_bind_text16(
   }else{
     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 ){
     return rc;
   }
index 494ace2c53f05bc3537f99b639c8b4a5625ee191..fbf21483d823ecd32a7acdd23cbcedd512f6997e 100644 (file)
@@ -544,9 +544,7 @@ int sqlite3VdbeList(
   */
   if( p->pTos==&p->aStack[4] ){
     for(i=0; i<5; i++){
-      if( p->aStack[i].flags & MEM_Dyn ){
-        sqliteFree(p->aStack[i].z);
-      }
+      sqlite3VdbeMemRelease(&p->aStack[i]);
       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.
 **
@@ -806,8 +756,8 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
           if( pMem->z!=0 && pMem->z!=pMem->z ){
             sqliteFree(pMem->z);
           }
-        }else if( pMem->flags&MEM_Dyn ){
-          sqliteFree(pMem->z);
+        }else{
+          sqlite3VdbeMemRelease(pMem);
         }
       }
       sqliteFree(pElem);
@@ -915,9 +865,7 @@ static void Cleanup(Vdbe *p){
   if( p->aStack ){
     Mem *pTos = p->pTos;
     while( pTos>=p->aStack ){
-      if( pTos->flags & MEM_Dyn ){
-        sqliteFree(pTos->z);
-      }
+      sqlite3VdbeMemRelease(pTos);
       pTos--;
     }
     p->pTos = pTos;
@@ -925,9 +873,7 @@ static void Cleanup(Vdbe *p){
   closeAllCursors(p);
   if( p->aMem ){
     for(i=0; i<p->nMem; i++){
-      if( p->aMem[i].flags & MEM_Dyn ){
-        sqliteFree(p->aMem[i].z);
-      }
+      sqlite3VdbeMemRelease(&p->aMem[i]);
     }
   }
   sqliteFree(p->aMem);
@@ -985,7 +931,10 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
 **
 ** 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 rc;
@@ -1007,13 +956,14 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
   }
 
   pColName = &(p->aColName[idx]);
-  if( N==0 ){
-    rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, 1);
+  if( N==P3_DYNAMIC || N==P3_STATIC ){
+    rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
   }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 ){
     pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
+    pColName->xDel = 0;
   }
   return rc;
 }
@@ -1396,9 +1346,7 @@ void sqlite3VdbeDelete(Vdbe *p){
 #endif
   }
   for(i=0; i<p->nVar; i++){
-    if( p->apVar[i].flags&MEM_Dyn ){
-      sqliteFree(p->apVar[i].z);
-    }
+    sqlite3VdbeMemRelease(&p->apVar[i]);
   }
   if( p->azColName16 ){
     for(i=0; i<p->nResColumn; i++){
@@ -1678,12 +1626,8 @@ int sqlite3VdbeRecordCompare(
     d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
 
     rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
-    if( mem1.flags&MEM_Dyn ){
-      sqliteFree(mem1.z);
-    }
-    if( mem2.flags&MEM_Dyn ){
-      sqliteFree(mem2.z);
-    }
+    sqlite3VdbeMemRelease(&mem1);
+    sqlite3VdbeMemRelease(&mem2);
     if( rc!=0 ){
       break;
     }
@@ -1753,9 +1697,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
   lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
   sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
   *rowid = v.i;
-  if( m.flags & MEM_Dyn ){
-    sqliteFree(m.z);
-  }
+  sqlite3VdbeMemRelease(&m);
   return SQLITE_OK;
 }
 
@@ -1791,8 +1733,6 @@ int sqlite3VdbeIdxKeyCompare(
   }
   lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
   *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
-  if( m.flags & MEM_Dyn ){
-    sqliteFree(m.z);
-  }
+  sqlite3VdbeMemRelease(&m);
   return SQLITE_OK;
 }
index b74c84e593580328debbca19b72c98b5e6521716..8265aaff3c2d1fdfc5b1e022c3a3723b3c6333a7 100644 (file)
@@ -54,9 +54,8 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
     if( rc!=SQLITE_OK ){
       return rc;
     }
-    if( pMem->flags&MEM_Dyn ){
-      sqliteFree(pMem->z);
-    }
+    sqlite3VdbeMemRelease(pMem);
+
     /* Result of sqlite3utfTranslate is currently always dynamically
     ** allocated and nul terminated. This might be altered as a performance
     ** enhancement later.
@@ -65,6 +64,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
     pMem->n = n;
     pMem->flags &= ~(MEM_Ephem | MEM_Short | MEM_Static);
     pMem->flags |= MEM_Str | MEM_Dyn | MEM_Term;
+    pMem->xDel = 0;
   }else{
     /* Must be translating between UTF-16le and UTF-16be. */
     int i;
@@ -98,6 +98,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
     return SQLITE_NOMEM;
   }
   pMem->flags |= MEM_Dyn|MEM_Term;
+  pMem->xDel = 0;
   memcpy(z, pMem->z, n );
   z[n] = 0;
   z[n+1] = 0;
@@ -129,6 +130,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
       return SQLITE_NOMEM;
     }
     pMem->flags |= MEM_Dyn|MEM_Term;
+    pMem->xDel = 0;
   }
   memcpy(z, pMem->z, n );
   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 ){
-    sqliteFree(p->z);
+    if( p->xDel ){
+      p->xDel((void *)p->z);
+    }else{
+      sqliteFree(p->z);
+    }
     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.
 */
 void sqlite3VdbeMemSetNull(Mem *pMem){
-  releaseMem(pMem);
+  sqlite3VdbeMemRelease(pMem);
   pMem->flags = MEM_Null;
   pMem->type = SQLITE_NULL;
 }
@@ -270,7 +279,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
 ** manifest type INTEGER.
 */
 void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
-  releaseMem(pMem);
+  sqlite3VdbeMemRelease(pMem);
   pMem->i = val;
   pMem->flags = MEM_Int;
   pMem->type = SQLITE_INTEGER;
@@ -281,7 +290,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
 ** manifest type REAL.
 */
 void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
-  releaseMem(pMem);
+  sqlite3VdbeMemRelease(pMem);
   pMem->r = val;
   pMem->flags = MEM_Real;
   pMem->type = SQLITE_FLOAT;
@@ -291,8 +300,9 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
 ** Copy the contents of memory cell pFrom into pTo.
 */
 int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
-  releaseMem(pTo);
+  sqlite3VdbeMemRelease(pTo);
   memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
+  pTo->xDel = 0;
   if( pTo->flags & (MEM_Str|MEM_Blob) ){
     pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
     pTo->flags |= MEM_Ephem;
@@ -309,9 +319,9 @@ int sqlite3VdbeMemSetStr(
   const char *z,      /* String pointer */
   int n,              /* Bytes in string, or negative */
   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 ){
     pMem->flags = MEM_Null;
     pMem->type = SQLITE_NULL;
@@ -319,14 +329,19 @@ int sqlite3VdbeMemSetStr(
   }
 
   pMem->z = (char *)z;
-  if( eCopy ){
+  if( xDel==SQLITE_STATIC ){
+    pMem->flags = MEM_Static;
+  }else if( xDel==SQLITE_TRANSIENT ){
     pMem->flags = MEM_Ephem;
   }else{
-    pMem->flags = MEM_Static;
+    pMem->flags = MEM_Dyn;
+    pMem->xDel = xDel;
   }
+
   pMem->enc = enc;
   pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
   pMem->n = n;
+
   switch( enc ){
     case 0:
       pMem->flags |= MEM_Blob;
@@ -352,7 +367,7 @@ int sqlite3VdbeMemSetStr(
     default:
       assert(0);
   }
-  if( eCopy ){
+  if( xDel==SQLITE_TRANSIENT ){
     return sqlite3VdbeMemMakeWriteable(pMem);
   }
   return SQLITE_OK;
@@ -510,6 +525,7 @@ int sqlite3VdbeMemFromBtree(
         return SQLITE_NOMEM;
       }
       pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
+      pMem->xDel = 0;
     }else{
       zData = &(pMem->zShort[0]);
       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){
-  Mem *p = (Mem *)v;
-  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;
+  sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, SQLITE_STATIC);
 }
 
 void sqlite3ValueFree(sqlite3_value *v){
index faaed152bfe89921a0da5645f4256a79ffe9e425..1a7a17cc161d824f899506b38586cf62ca9baf85 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # 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]
 source $testdir/tester.tcl
@@ -336,4 +336,44 @@ do_test func-11.1 {
   }
 } [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
+
+
+
index 023b9a125441440bdcaeb3515dc2b22ce0b8f583..63faa38fc63c4a2fe87006ae9a14ffeebd7fd50e 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # 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]
 source $testdir/tester.tcl
@@ -220,7 +220,7 @@ do_test index-7.3 {
     SELECT name FROM sqlite_master 
     WHERE type='index' AND tbl_name='test1'
   }
-} {{(test1 autoindex 1)}}
+} {sqlite_autoindex_test1_1}
 do_test index-7.4 {
   execsql {DROP table test1}
   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}
 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
+
index c159fb493d04871bae73e5f6f89428adf06dd1fd..dfb24c337481692640e269f4f3a2ed7b5168424c 100644 (file)
@@ -13,7 +13,7 @@
 # This file implements tests for the special processing associated
 # 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]
 source $testdir/tester.tcl
@@ -34,7 +34,7 @@ do_test intpkey-1.1 {
     SELECT name FROM sqlite_master
     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
 # there is no associated index.
index 3314800db215d41b608768b6b7c6f87e71e8713a..989c8d9004343b424c42a4d30dc66c12abe5409b 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # 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]
 source $testdir/tester.tcl
@@ -96,13 +96,13 @@ do_test table-2.1 {
 do_test table-2.1b {
   set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg]
   lappend v $msg
-} {1 {table sqlite_master already exists}}
+} {1 {object name reserved for internal use: sqlite_master}}
 do_test table-2.1c {
   db close
   sqlite db test.db
   set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg]
   lappend v $msg
-} {1 {table sqlite_master already exists}}
+} {1 {object name reserved for internal use: sqlite_master}}
 do_test table-2.1d {
   execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'}
 } {}