]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make sure sqlite3_value_bytes() does not reformat the content after a
authordrh <drh@noemail.net>
Fri, 27 Apr 2007 17:16:20 +0000 (17:16 +0000)
committerdrh <drh@noemail.net>
Fri, 27 Apr 2007 17:16:20 +0000 (17:16 +0000)
call to sqlite3_value_blob().  Add documentation to explain this hazard.
Add many new tests.  Ticket #2321. (CVS 3880)

FossilOrigin-Name: e92bd97a3726bbb7978489e2994747127c4aefcf

manifest
manifest.uuid
src/func.c
src/test1.c
src/vdbeapi.c
test/ptrchng.test [new file with mode: 0644]
www/capi3.tcl
www/capi3ref.tcl

index b33caf688f75896f62fa310e5f0c3ec5affa46ed..24215d2264d3bb5a9f0899f3533f367834f8e1c3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Extra\stests\sfor\sincremental\svacuum.\s(CVS\s3879)
-D 2007-04-27T07:55:38
+C Make\ssure\ssqlite3_value_bytes()\sdoes\snot\sreformat\sthe\scontent\safter\sa\ncall\sto\ssqlite3_value_blob().\s\sAdd\sdocumentation\sto\sexplain\sthis\shazard.\nAdd\smany\snew\stests.\s\sTicket\s#2321.\s(CVS\s3880)
+D 2007-04-27T17:16:20
 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -68,7 +68,7 @@ F src/date.c 94a6777df13d2aaacd19de080d9e8d3444364133
 F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
 F src/expr.c 2f0f9f89efe9170e5e6ca5d5e93a9d5896fff5ac
-F src/func.c b989aa0ecc66a6d48b46f297299d52f12d84bce9
+F src/func.c 89d8547a9cb1c5ad8e0b86b3d74de56e5254254b
 F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
 F src/insert.c 413cc06990cb3c401e64e596776c1e43934f8841
@@ -102,7 +102,7 @@ F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
 F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0
 F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
 F src/tclsqlite.c ec69eb9ad56d03fbf7570ca1ca5ea947d1ec4b6f
-F src/test1.c 53b7eb5cba0012f592b5860f6ad3b5a3f887eb1e
+F src/test1.c f1271d41719d05348e6dc39722260e17b8d7ddc1
 F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
 F src/test3.c 65f92247cf8592854e9bf5115b3fb711f8b33280
 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
@@ -128,7 +128,7 @@ F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
 F src/vdbe.c a3cf3792fdbd382f756eb7eb50006b2f3f8d4283
 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
 F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132
-F src/vdbeapi.c 245263aa2d70d87b1201753cddc881996f219843
+F src/vdbeapi.c 37fc2818bec64b361af73f3935699107bab0e625
 F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e
 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
 F src/vdbemem.c 981a113405bd9b80aeb71fe246a2f01708e8a8f7
@@ -297,6 +297,7 @@ F test/pagesize.test e0a8b3fe80f8b8e808d94a00734c7a18c76c407e
 F test/pragma.test fecb7085f58d9fb5172a5c0b63fd3b25c7bfb414
 F test/printf.test 483b9fe75ffae1fb27328bdce5560b452ba83577
 F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
+F test/ptrchng.test 1c712dd6516e1377471744fa765e41c79a357da6
 F test/quick.test 8e7ffe36a1c920cdcce5d641646abde2dafd764b
 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
 F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
@@ -418,8 +419,8 @@ F www/arch2b.fig d22a2c9642d584b89d4088b1e51e2bb0f7c04bed
 F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0
 F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06
 F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e
-F www/capi3.tcl 7a7cc225fe02eb7ab861a6019b08baa0014409e1
-F www/capi3ref.tcl 80178d2697e97236c208a2a6a507e82d121acc71
+F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716
+F www/capi3ref.tcl 0d742d6bd59bc51bbb4be014e7ea47e97786d318
 F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58
 F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e
 F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084
@@ -463,7 +464,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 4d4180d6474d8d74460fb9333580b9b60c89f353
-R cb55629cd4ed6b5c3bd0582e6bc3a138
-U danielk1977
-Z f3e9134088bb4d98704fded975f43270
+P 40ba6493e9e8ba135552a2a0943ab499713ac001
+R ae6e82023418585801b4f01168703216
+U drh
+Z e4fdef4577a3571a48a38a52b01018a7
index dfc8508b511a3a2ebf5254d42e42776c786f914e..b27b17606858b0903a78ee867587ccf07b9b99df 100644 (file)
@@ -1 +1 @@
-40ba6493e9e8ba135552a2a0943ab499713ac001
\ No newline at end of file
+e92bd97a3726bbb7978489e2994747127c4aefcf
\ No newline at end of file
index ad1bb59155ee15f50b47c138124392897285339f..86d5da62328ed8e9ffd1a1ecd33ff34018932ba0 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.141 2007/04/27 01:18:03 drh Exp $
+** $Id: func.c,v 1.142 2007/04/27 17:16:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -215,11 +215,12 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
 static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   char *z1;
   const char *z2;
-  int i;
+  int i, n;
   if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+  n = sqlite3_value_bytes(argv[0]);
   z2 = (char*)sqlite3_value_text(argv[0]);
   if( z2 ){
-    z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
+    z1 = sqlite3_malloc(n+1);
     if( z1 ){
       strcpy(z1, z2);
       for(i=0; z1[i]; i++){
@@ -232,11 +233,12 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
 static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   char *z1;
   const char *z2;
-  int i;
+  int i, n;
   if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+  n = sqlite3_value_bytes(argv[0]);
   z2 = (char*)sqlite3_value_text(argv[0]);
   if( z2 ){
-    z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
+    z1 = sqlite3_malloc(n+1);
     if( z1 ){
       strcpy(z1, z2);
       for(i=0; z1[i]; i++){
@@ -703,15 +705,15 @@ static void replaceFunc(
   int i, j;                /* Loop counters */
 
   assert( argc==3 );
+  nStr = sqlite3_value_bytes(argv[0]);
   zStr = sqlite3_value_text(argv[0]);
   if( zStr==0 ) return;
-  nStr = sqlite3_value_bytes(argv[0]);
+  nPattern = sqlite3_value_bytes(argv[1]);
   zPattern = sqlite3_value_text(argv[1]);
   if( zPattern==0 || zPattern[0]==0 ) return;
-  nPattern = sqlite3_value_bytes(argv[1]);
+  nRep = sqlite3_value_bytes(argv[2]);
   zRep = sqlite3_value_text(argv[2]);
   if( zRep==0 ) return;
-  nRep = sqlite3_value_bytes(argv[2]);
   if( nPattern>=nRep ){
     nOut = nStr;
   }else{
@@ -754,9 +756,9 @@ static void trimFunc(
   if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
     return;
   }
+  nIn = sqlite3_value_bytes(argv[0]);
   zIn = sqlite3_value_text(argv[0]);
   if( zIn==0 ) return;
-  nIn = sqlite3_value_bytes(argv[0]);
   if( argc==1 ){
     static const unsigned char zSpace[] = " ";
     zCharSet = zSpace;
index 2454e7d2925f4b15f93b0444022535d9ddb0630f..1d765b1efc6962aefc92dd0c3a7cde84368fabe2 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.239 2007/04/23 23:56:31 drh Exp $
+** $Id: test1.c,v 1.240 2007/04/27 17:16:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -557,8 +557,9 @@ static void t1_ifnullFunc(
   int i;
   for(i=0; i<argc; i++){
     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
+      int n = sqlite3_value_bytes(argv[i]);
       sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
-          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
+          n, SQLITE_TRANSIENT);
       break;
     }
   }
@@ -707,6 +708,81 @@ static void tkt2213Function(
   }
 }
 
+/*
+** The following SQL function takes 4 arguments.  The 2nd and
+** 4th argument must be one of these strings:  'text', 'text16',
+** or 'blob' corresponding to API functions
+**
+**      sqlite3_value_text()
+**      sqlite3_value_text16()
+**      sqlite3_value_blob()
+**
+** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
+** corresponding to APIs:
+**
+**      sqlite3_value_bytes()
+**      sqlite3_value_bytes16()
+**      noop
+**
+** The APIs designated by the 2nd through 4th arguments are applied
+** to the first argument in order.  If the pointers returned by the
+** second and fourth are different, this routine returns 1.  Otherwise,
+** this routine returns 0.
+**
+** This function is used to test to see when returned pointers from
+** the _text(), _text16() and _blob() APIs become invalidated.
+*/
+static void ptrChngFunction(
+  sqlite3_context *context, 
+  int argc,  
+  sqlite3_value **argv
+){
+  const void *p1, *p2;
+  const char *zCmd;
+  if( argc!=4 ) return;
+  zCmd = (const char*)sqlite3_value_text(argv[1]);
+  if( zCmd==0 ) return;
+  if( strcmp(zCmd,"text")==0 ){
+    p1 = (const void*)sqlite3_value_text(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+  }else if( strcmp(zCmd, "text16")==0 ){
+    p1 = (const void*)sqlite3_value_text16(argv[0]);
+#endif
+  }else if( strcmp(zCmd, "blob")==0 ){
+    p1 = (const void*)sqlite3_value_blob(argv[0]);
+  }else{
+    return;
+  }
+  zCmd = (const char*)sqlite3_value_text(argv[2]);
+  if( zCmd==0 ) return;
+  if( strcmp(zCmd,"bytes")==0 ){
+    sqlite3_value_bytes(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+  }else if( strcmp(zCmd, "bytes16")==0 ){
+    sqlite3_value_bytes16(argv[0]);
+#endif
+  }else if( strcmp(zCmd, "noop")==0 ){
+    /* do nothing */
+  }else{
+    return;
+  }
+  zCmd = (const char*)sqlite3_value_text(argv[3]);
+  if( zCmd==0 ) return;
+  if( strcmp(zCmd,"text")==0 ){
+    p2 = (const void*)sqlite3_value_text(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+  }else if( strcmp(zCmd, "text16")==0 ){
+    p2 = (const void*)sqlite3_value_text16(argv[0]);
+#endif
+  }else if( strcmp(zCmd, "blob")==0 ){
+    p2 = (const void*)sqlite3_value_blob(argv[0]);
+  }else{
+    return;
+  }
+  sqlite3_result_int(context, p1!=p2);
+}
+
+
 /*
 ** Usage:  sqlite_test_create_function DB
 **
@@ -754,6 +830,10 @@ static int test_create_function(
     rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0, 
           tkt2213Function, 0, 0);
   }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0, 
+          ptrChngFunction, 0, 0);
+  }
 
 #ifndef SQLITE_OMIT_UTF16
   /* Use the sqlite3_create_function16() API here. Mainly for fun, but also 
@@ -3129,8 +3209,8 @@ static int test_column_blob(
   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
 
-  pBlob = sqlite3_column_blob(pStmt, col);
   len = sqlite3_column_bytes(pStmt, col);
+  pBlob = sqlite3_column_blob(pStmt, col);
   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
   return TCL_OK;
 }
index 2e67cbdcb251018ecdc0e0f8100450f3e4a418f6..bd6d1d41020bf493d81ad38ff33ae4d4e29d85b3 100644 (file)
@@ -37,6 +37,9 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
 const void *sqlite3_value_blob(sqlite3_value *pVal){
   Mem *p = (Mem*)pVal;
   if( p->flags & (MEM_Blob|MEM_Str) ){
+    if( (p->flags & MEM_Term)==0 ){
+      p->flags &= ~MEM_Str;
+    }
     return p->z;
   }else{
     return sqlite3_value_text(pVal);
diff --git a/test/ptrchng.test b/test/ptrchng.test
new file mode 100644 (file)
index 0000000..a26d96f
--- /dev/null
@@ -0,0 +1,217 @@
+# 2007 April 27
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# The focus of the tests in this file are to verify that the
+# underlying TEXT or BLOB representation of an sqlite3_value
+# changes appropriately when APIs from the following set are
+# called:
+#
+#     sqlite3_value_text()
+#     sqlite3_value_text16()
+#     sqlite3_value_blob()
+#     sqlite3_value_bytes()
+#     sqlite3_value_bytes16()
+#
+# $Id: ptrchng.test,v 1.1 2007/04/27 17:16:22 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Register the "pointer_change" SQL function.
+#
+sqlite3_create_function db
+
+do_test ptrchng-1.1 {
+  execsql {
+    CREATE TABLE t1(x INTEGER PRIMARY KEY, y BLOB);
+    INSERT INTO t1 VALUES(1, 'abc');
+    INSERT INTO t1 VALUES(2, 
+       'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234356789');
+    INSERT INTO t1 VALUES(3, x'626c6f62');
+    INSERT INTO t1 VALUES(4,
+ x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324'
+    );
+    SELECT count(*) FROM t1;
+  }
+} {4}
+
+# For the short entries that fit in the Mem.zBuf[], the pointer should
+# never change regardless of what type conversions occur.
+#
+do_test ptrchng-2.1 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=1
+  }
+} {0}
+do_test ptrchng-2.2 {
+  execsql {
+    SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=1
+  }
+} {0}
+ifcapable utf16 {
+  do_test ptrchng-2.3 {
+    execsql {
+      SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=1
+    }
+  } {0}
+  do_test ptrchng-2.4 {
+    execsql {
+      SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=1
+    }
+  } {0}
+  do_test ptrchng-2.5 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=1
+    }
+  } {0}
+  do_test ptrchng-2.6 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=1
+    }
+  } {0}
+}
+do_test ptrchng-2.11 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=3
+  }
+} {0}
+do_test ptrchng-2.12 {
+  execsql {
+    SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=3
+  }
+} {0}
+ifcapable utf16 {
+  do_test ptrchng-2.13 {
+    execsql {
+      SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=3
+    }
+  } {0}
+  do_test ptrchng-2.14 {
+    execsql {
+      SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=3
+    }
+  } {0}
+  do_test ptrchng-2.15 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=3
+    }
+  } {0}
+  do_test ptrchng-2.16 {
+btree_breakpoint
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=3
+    }
+  } {0}
+}
+
+# For the long entries that do not fit in the Mem.zBuf[], the pointer
+# should change sometimes.
+#
+do_test ptrchng-3.1 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=2
+  }
+} {0}
+do_test ptrchng-3.2 {
+  execsql {
+    SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=2
+  }
+} {0}
+ifcapable utf16 {
+  do_test ptrchng-3.3 {
+    execsql {
+      SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=2
+    }
+  } {1}
+  do_test ptrchng-3.4 {
+    execsql {
+      SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=2
+    }
+  } {1}
+  do_test ptrchng-3.5 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=2
+    }
+  } {0}
+  do_test ptrchng-3.6 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=2
+    }
+  } {1}
+}
+do_test ptrchng-3.11 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=4
+  }
+} {0}
+do_test ptrchng-3.12 {
+  execsql {
+    SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=4
+  }
+} {0}
+ifcapable utf16 {
+  do_test ptrchng-3.13 {
+    execsql {
+      SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=4
+    }
+  } {1}
+  do_test ptrchng-3.14 {
+    execsql {
+      SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=4
+    }
+  } {1}
+  do_test ptrchng-3.15 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=4
+    }
+  } {0}
+  do_test ptrchng-3.16 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=4
+    }
+  } {1}
+}
+
+# A call to _bytes() should never reformat a _text() or _blob().
+#
+do_test ptrchng-4.1 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'bytes', 'text') FROM t1
+  }
+} {0 0 0 0}
+do_test ptrchng-4.2 {
+  execsql {
+    SELECT pointer_change(y, 'blob', 'bytes', 'blob') FROM t1
+  }
+} {0 0 0 0}
+
+# A call to _blob() should never trigger a reformat
+#
+do_test ptrchng-5.1 {
+  execsql {
+    SELECT pointer_change(y, 'text', 'bytes', 'blob') FROM t1
+  }
+} {0 0 0 0}
+ifcapable utf16 {
+  do_test ptrchng-5.2 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1
+    }
+  } {0 0 0 0}
+  do_test ptrchng-5.3 {
+    execsql {
+      SELECT pointer_change(y, 'text16', 'bytes16', 'blob') FROM t1
+    }
+  } {0 0 0 0}
+}
+
+finish_test
index 2e1e0ec1809fef7d65be7bce2e97478e68e8b16b..149cf7f0adc7f480fde0f70aceec240800238ba5 100644 (file)
@@ -1,4 +1,4 @@
-set rcsid {$Id: capi3.tcl,v 1.9 2005/03/11 04:39:58 drh Exp $}
+set rcsid {$Id: capi3.tcl,v 1.10 2007/04/27 17:16:22 drh Exp $}
 source common.tcl
 header {C/C++ Interface For SQLite Version 3}
 
@@ -324,6 +324,56 @@ sqlite3_column_type().  If a different format is requested, the data
 is converted automatically.
 </p>
 
+<p>
+Data format conversions can invalidate the pointer returned by
+prior calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
+sqlite3_column_text16().  Pointers might be invalided in the following
+cases:
+</p>
+<ul>
+<li><p>
+The initial content is a BLOB and sqlite3_column_text() 
+or sqlite3_column_text16()
+is called.  A zero-terminator might need to be added to the string.
+</p></li>
+<li><p>
+The initial content is UTF-8 text and sqlite3_column_bytes16() or
+sqlite3_column_text16() is called.  The content must be converted to UTF-16.
+</p></li>
+<li><p>
+The initial content is UTF-16 text and sqlite3_column_bytes() or
+sqlite3_column_text() is called.  The content must be converted to UTF-8.
+</p></li>
+</ul>
+<p>
+Note that conversions between UTF-16be and UTF-16le 
+are always done in place and do
+not invalidate a prior pointer, though of course the content of the buffer
+that the prior pointer points to will have been modified.  Other kinds
+of conversion are done in place when it is possible, but sometime it is
+not possible and in those cases prior pointers are invalidated.  
+</p>
+
+<p>
+The safest and easiest to remember policy is this: assume that any
+result from
+<ul>
+<li>sqlite3_column_blob(),</li>
+<li>sqlite3_column_text(), or</li>
+<li>sqlite3_column_text16()</li>
+</ul>
+is invalided by subsequent calls to 
+<ul>
+<li>sqlite3_column_bytes(),</li>
+<li>sqlite3_column_bytes16(),</li>
+<li>sqlite3_column_text(), or</li>
+<li>sqlite3_column_text16().</li>
+</ul>
+This means that you should always call sqlite3_column_bytes() or
+sqlite3_column_bytes16() <u>before</u> calling sqlite3_column_blob(),
+sqlite3_column_text(), or sqlite3_column_text16().
+</p>
+
 <h4>2.3 User-defined functions</h4>
 
 <p>
index b175ada5d535849305d803b281b585270bc3019d..aaa88ea1ed42bd4994953a01edbdb9bbfa953bcc 100644 (file)
@@ -1,4 +1,4 @@
-set rcsid {$Id: capi3ref.tcl,v 1.55 2007/04/16 15:35:24 drh Exp $}
+set rcsid {$Id: capi3ref.tcl,v 1.56 2007/04/27 17:16:22 drh Exp $}
 source common.tcl
 header {C/C++ Interface For SQLite Version 3}
 puts {
@@ -432,15 +432,51 @@ int sqlite3_column_type(sqlite3_stmt*, int iCol);
 
   Note that when type conversions occur, pointers returned by prior
   calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
-  sqlite3_column_text16() may be invalidated.  So, for example, if
-  you initially call sqlite3_column_text() and get back a pointer to
-  a UTF-8 string, then you call sqlite3_column_text16(), after the
-  call to sqlite3_column_text16() the pointer returned by the prior
-  call to sqlite3_column_text() will likely point to deallocated memory.
-  Attempting to use the original pointer might lead to heap corruption
-  or a segfault.  Note also that calls  to sqlite3_column_bytes()
-  and sqlite3_column_bytes16() can also cause type conversion that
-  and deallocate prior buffers.  Use these routines carefully.
+  sqlite3_column_text16() may be invalidated. 
+  Type conversions and pointer invalidations might occur
+  in the following cases:
+
+  <ul>
+  <li><p>
+  The initial content is a BLOB and sqlite3_column_text() 
+  or sqlite3_column_text16()
+  is called.  A zero-terminator might need to be added to the string.
+  </p></li>
+  <li><p>
+  The initial content is UTF-8 text and sqlite3_column_bytes16() or
+  sqlite3_column_text16() is called.  The content must be converted to UTF-16.
+  </p></li>
+  <li><p>
+  The initial content is UTF-16 text and sqlite3_column_bytes() or
+  sqlite3_column_text() is called.  The content must be converted to UTF-8.
+  </p></li>
+  </ul>
+
+  Conversions between UTF-16be and UTF-16le 
+  are always done in place and do
+  not invalidate a prior pointer, though of course the content of the buffer
+  that the prior pointer points to will have been modified.  Other kinds
+  of conversion are done in place when it is possible, but sometime it is
+  not possible and in those cases prior pointers are invalidated.  
+
+  The safest and easiest to remember policy is this: assume that any
+  result from
+  <ul>
+  <li>sqlite3_column_blob(),</li>
+  <li>sqlite3_column_text(), or</li>
+  <li>sqlite3_column_text16()</li>
+  </ul>
+  is invalided by subsequent calls to 
+  <ul>
+  <li>sqlite3_column_bytes(),</li>
+  <li>sqlite3_column_bytes16(),</li>
+  <li>sqlite3_column_text(), or</li>
+  <li>sqlite3_column_text16().</li>
+  </ul>
+  This means that you should always call sqlite3_column_bytes() or
+  sqlite3_column_bytes16() <u>before</u> calling sqlite3_column_blob(),
+  sqlite3_column_text(), or sqlite3_column_text16().
+
 }
 
 api {} {
@@ -1491,6 +1527,12 @@ int sqlite3_value_type(sqlite3_value*);
 
  See the documentation under sqlite3_column_blob for additional
  information.
+
+ Please pay particular attention to the fact that the pointer that
+ is returned from sqlite3_value_blob(), sqlite3_value_text(), or
+ sqlite3_value_text16() can be invalidated by a subsequent call to
+ sqlite3_value_bytes(), sqlite3_value_bytes16(), sqlite_value_text(),
+ or sqlite3_value_text16().  
 }
 
 api {} {