diff --git a/manifest b/manifest
index cc0aa52cb7..fa52920b33 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\ssqlite3_value\sobject\snow\scarries\san\ssqlite3*\spointer\sto\suse\sfor\nrecording\smalloc\sfailures.\s\sThis\seliminates\sthe\sneed\sto\spass\ssqlite3*\npointers\sinto\smany\sinternal\sinterfaces.\s\sAlso\sadded\smore\smutexing.\s(CVS\s4263)
-D 2007-08-21T19:33:56
+C All\smutexing\sand\slocking\sappears\sto\sbe\sin\splace.\s\sNow\swe\sjust\shave\sto\ntest\sit\sand\smake\sit\sall\swork.\s(CVS\s4264)
+D 2007-08-21T20:25:40
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -124,7 +124,7 @@ F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
F src/select.c 98c367bce3f38c5adfcc97de9ab5c79b0e5dc2b2
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
-F src/sqlite.h.in 95e159919060f9c6e060ff420ce17490f7b6a0f3
+F src/sqlite.h.in b2a7484c024c42f2e639f289beb7c8db36513a2c
F src/sqlite3ext.h 647a6b8a8f76ff6c9611e4a071531d8e63ff2d6b
F src/sqliteInt.h 23eb6a5b1f10d5d3d34c3c7846b7c3b93acf1276
F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
@@ -159,7 +159,7 @@ F src/vacuum.c 318ccae7c4e3ddf241aeaee4d2611bfe1949a373
F src/vdbe.c 9d4d00589c174aad9a616f1615464ddddebba0ec
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
F src/vdbeInt.h 39fb069ce04137545ca0bc790f80ddc64a8c99d9
-F src/vdbeapi.c 09eb4fe5ce6e8e4558ca3fa1e22241f2d3895bf0
+F src/vdbeapi.c e12f99aa859118afbffff67eb32df36d564b5c80
F src/vdbeaux.c b0aeed4ff33352904b392ee6c7408bae5b141b9b
F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
@@ -558,7 +558,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 7428732b1fa04b83eda0a3539834693ef351313e
-R 913d5d6bd631d176ac289a9e0cf82ff0
+P 9287276191a582c1cf7cf6b71d8399727d8e534d
+R c2481d632c284d895f66ae3d4866a0ab
U drh
-Z c581f4a42a4b4dc59e9659821c9fdece
+Z aa5c15d669e0ef0f762ec1f2d438a5a0
diff --git a/manifest.uuid b/manifest.uuid
index d5508f39d3..780479153a 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-9287276191a582c1cf7cf6b71d8399727d8e534d
\ No newline at end of file
+0f7941aef976aa4f3be3e0046edd1ae042e5d9a3
\ No newline at end of file
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index ba1731864d..a4bd04f53e 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.234 2007/08/21 19:33:56 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.235 2007/08/21 20:25:40 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -1745,6 +1745,10 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
**
** These APIs are only available if the library was compiled with the
** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
+**
+** If two or more threads call one or more of these routines against the same
+** prepared statement and column at the same time then the results are
+** undefined.
*/
const char *sqlite3_column_database_name(sqlite3_stmt*,int);
const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
@@ -1905,17 +1909,27 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Results Values From A Query
**
-** These routines return information about the information
-** in a single column of the current result row of a query. In every
+** These routines return information about
+** a single column of the current result row of a query. In every
** case the first argument is a pointer to the
** [sqlite3_stmt | SQL statement] that is being
-** evaluate (the [sqlite3_stmt*] that was returned from
+** evaluated (the [sqlite3_stmt*] that was returned from
** [sqlite3_prepare_v2()] or one of its variants) and
** the second argument is the index of the column for which information
-** should be returned. The left-most column has an index of 0.
+** should be returned. The left-most column of the result set
+** has an index of 0.
**
** If the SQL statement is not currently point to a valid row, or if the
-** the column index is out of range, the result is undefined.
+** the column index is out of range, the result is undefined.
+** These routines may only be called when the most recent call to
+** [sqlite3_step()] has returned [SQLITE_ROW] and neither
+** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently.
+** If any of these routines are called after [sqlite3_reset()] or
+** [sqlite3_finalize()] or after [sqlite3_step()] has returned
+** something other than [SQLITE_ROW], the results are undefined.
+** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
+** are called from a different thread while any of these routines
+** are pending, then the results are undefined.
**
** The sqlite3_column_type() routine returns
** [SQLITE_INTEGER | datatype code] for the initial data type
@@ -2019,6 +2033,13 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** find the size of the result. Do not mix call to sqlite3_column_text() or
** sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not
** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes().
+**
+** The pointers returned are valid until a type conversion occurs as
+** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
+** [sqlite3_finalize()] is called. The memory space used to hold strings
+** and blobs is freed automatically. Do not pass the pointers returned
+** [sqlite3_column_blob()], [sqlite_column_text()], etc. into
+** [sqlite3_free()].
*/
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
@@ -2211,6 +2232,9 @@ void sqlite3_thread_cleanup(void);
**
** These routines must be called from the same thread as
** the SQL function that supplied the sqlite3_value* parameters.
+** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()]
+** interface, then these routines should be called from the same thread
+** that ran [sqlite3_column_value()].
*/
const void *sqlite3_value_blob(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
@@ -3311,6 +3335,13 @@ int sqlite3_mutex_try(sqlite3_mutex*);
void sqlite3_mutex_leave(sqlite3_mutex*);
int sqlite3_mutex_held(sqlite3_mutex*);
int sqlite3_mutex_notheld(sqlite3_mutex*);
+
+/*
+** CAPI3REF: Mutex Types
+**
+** The [sqlite3_mutex_alloc()] interface takes a single argument
+** which is one of these integer constants.
+*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
#define SQLITE_MUTEX_STATIC_MASTER 2
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 20767fd628..cf8b6dc5ff 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -137,7 +137,6 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
int sqlite3_value_type(sqlite3_value* pVal){
return pVal->type;
}
-/* sqlite3_value_numeric_type() defined in vdbe.c */
/**************************** sqlite3_result_ *******************************
** The following routines are used by user-defined functions to specify
@@ -150,28 +149,35 @@ void sqlite3_result_blob(
void (*xDel)(void *)
){
assert( n>=0 );
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
}
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
}
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
}
void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetInt64(&pCtx->s, iVal);
}
void sqlite3_result_null(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetNull(&pCtx->s);
}
void sqlite3_result_text(
@@ -180,6 +186,7 @@ void sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
}
#ifndef SQLITE_OMIT_UTF16
@@ -189,6 +196,7 @@ void sqlite3_result_text16(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
}
void sqlite3_result_text16be(
@@ -197,6 +205,7 @@ void sqlite3_result_text16be(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
}
void sqlite3_result_text16le(
@@ -205,18 +214,22 @@ void sqlite3_result_text16le(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemCopy(&pCtx->s, pValue);
}
void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetZeroBlob(&pCtx->s, n);
}
/* Force an SQLITE_TOOBIG error. */
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1);
}
@@ -535,14 +548,21 @@ int sqlite3_data_count(sqlite3_stmt *pStmt){
** of NULL.
*/
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
- Vdbe *pVm = (Vdbe *)pStmt;
- int vals = sqlite3_data_count(pStmt);
- if( pVm==0 || pVm->resOnStack==0 || i>=pVm->nResColumn || i<0 ){
+ Vdbe *pVm;
+ int vals;
+ Mem *pOut;
+
+ pVm = (Vdbe *)pStmt;
+ if( pVm && pVm->resOnStack && inResColumn && i>=0 ){
+ sqlite3_mutex_enter(pVm->db->mutex);
+ vals = sqlite3_data_count(pStmt);
+ pOut = &pVm->pTos[(1-vals)+i];
+ }else{
static const Mem nullMem = {{0}, 0.0, 0, "", 0, MEM_Null, SQLITE_NULL };
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
- return (Mem*)&nullMem;
+ pOut = (Mem*)&nullMem;
}
- return &pVm->pTos[(1-vals)+i];
+ return pOut;
}
/*
@@ -552,7 +572,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** malloc() has failed, the threads mallocFailed flag is cleared and the result
** code of statement pStmt set to SQLITE_NOMEM.
**
-** Specificly, this is called from within:
+** Specifically, this is called from within:
**
** sqlite3_column_int()
** sqlite3_column_int64()
@@ -572,7 +592,10 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** and _finalize() will return NOMEM.
*/
Vdbe *p = (Vdbe *)pStmt;
- p->rc = sqlite3ApiExit(0, p->rc);
+ if( p ){
+ p->rc = sqlite3ApiExit(p->db, p->rc);
+ sqlite3_mutex_leave(p->db->mutex);
+ }
}
/**************************** sqlite3_column_ *******************************
@@ -620,7 +643,9 @@ const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
return val;
}
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
- return columnMem(pStmt, i);
+ sqlite3_value *pOut = columnMem(pStmt, i);
+ columnMallocFailure(pStmt);
+ return pOut;
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
@@ -630,7 +655,9 @@ const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_type( columnMem(pStmt,i) );
+ int iType = sqlite3_value_type( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return iType;
}
/* The following function is experimental and subject to change or
@@ -662,20 +689,28 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
- const void *ret;
+ const void *ret = 0;
Vdbe *p = (Vdbe *)pStmt;
- int n = sqlite3_column_count(pStmt);
+ int n;
+
- if( p==0 || N>=n || N<0 ){
- return 0;
+ if( p!=0 ){
+ n = sqlite3_column_count(pStmt);
+ if( N=0 ){
+ N += useType*n;
+ ret = xFunc(&p->aColName[N]);
+
+#if 0
+ /* A malloc may have failed inside of the xFunc() call. If this
+ ** is the case, clear the mallocFailed flag and return NULL.
+ */
+ if( p->db && p->db->mallocFailed ){
+ p->db->mallocFailed = 0;
+ ret = 0;
+ }
+#endif
+ }
}
- N += useType*n;
- ret = xFunc(&p->aColName[N]);
-
- /* A malloc may have failed inside of the xFunc() call. If this is the case,
- ** clear the mallocFailed flag and return NULL.
- */
- sqlite3ApiExit(0, 0);
return ret;
}