From 10deb35995422c8987d8f27593df2cb28c4ed66b Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 30 Aug 2023 15:20:15 +0000
Subject: [PATCH 1/9] New experimental API for attaching client data to a
database connection.
FossilOrigin-Name: d542837fdb42ebe810fc99225860d2cc7e6dd829a635bde820a09beff6bcb481
---
manifest | 21 +++++++------
manifest.uuid | 2 +-
src/main.c | 57 ++++++++++++++++++++++++++++++++++
src/sqlite.h.in | 81 ++++++++++++++++++++++++++++++++++++++++---------
src/sqliteInt.h | 12 ++++++++
5 files changed, 148 insertions(+), 25 deletions(-)
diff --git a/manifest b/manifest
index 0e6f1ff076..e4e672b2aa 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C When\sa\sJS\sSQLTester\sscript\sthrows,\sreport\sthe\sexception\sdetails\sback\sto\sthe\sUI\sregardless\sof\swhether\sit's\sfatal.
-D 2023-08-30T14:20:02.025
+C New\sexperimental\sAPI\sfor\sattaching\sclient\sdata\sto\sa\sdatabase\sconnection.
+D 2023-08-30T15:20:15.256
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 6287177c498427658b892fd816434d36bf9b85b33bf65d5280b897c3b34cee8c
+F src/main.c 5c28d8b05896007a820fb1f4b9089c8e237813bf51f7de2ebc7ce88cb0f0b2ba
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -707,10 +707,10 @@ F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 5f545a2c8702d4d3430bbb188cfec47d6c122d899061ef00cbe56af14591c574
F src/shell.c.in 2f9be25294b68b07e7e81f0adcec4475aba6011b64f160e414efe226910c4d7b
-F src/sqlite.h.in 73a366c1c45d5ac9888cfe81c458826a44498531d106cfb4f328193ab5f6f17d
+F src/sqlite.h.in 9f1ae109025327841ecd4f1c7fbe5550a59959ccea444e4d6e388ee5d4135602
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
-F src/sqliteInt.h 025ed58a41968ef80d64cdc194caa8dd207b0256b147253d762fdac7a62408f9
+F src/sqliteInt.h 985a09af9a8ce7862318ff77550b9b172e684b5a10e55dd96796e08e48f6dbca
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -2115,8 +2115,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b530792a514d95c4e8f93cf2170d9fc4de367055fa1704fc171551c946024fa9
-R 27c4b366fbb2810d013255774a7479ce
-U stephan
-Z 3efc7b20eec1af6f89785f42be992e20
+P 273d3b05f630d399d42914e95c416b107b4746bbef129cfba9d00fd921666261
+R ea42982c5b96fe2a959e6a802572e9d0
+T *branch * db-client-data
+T *sym-db-client-data *
+T -sym-trunk *
+U drh
+Z da4f47e3406f7c1072eed31bdeabf988
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index def26b8ea3..0cd4c66fa4 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-273d3b05f630d399d42914e95c416b107b4746bbef129cfba9d00fd921666261
\ No newline at end of file
+d542837fdb42ebe810fc99225860d2cc7e6dd829a635bde820a09beff6bcb481
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index b8f2622612..994d82ed97 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1253,6 +1253,14 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
#endif
+ while( db->pDbData ){
+ DbClientData *p = db->pDbData;
+ db->pDbData = p->pNext;
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ sqlite3_free(p);
+ }
+
/* Convert the connection into a zombie and then close it.
*/
db->eOpenState = SQLITE_STATE_ZOMBIE;
@@ -3710,6 +3718,55 @@ int sqlite3_collation_needed16(
}
#endif /* SQLITE_OMIT_UTF16 */
+/*
+** Find existing client data.
+*/
+void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
+ DbClientData *p;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){}
+ return p;
+}
+
+/*
+** Add new client data to a database connection.
+*/
+int sqlite3_set_clientdata(
+ sqlite3 *db, /* Attach client data to this connection */
+ const char *zName, /* Name of the client data */
+ void *pData, /* The client data itself */
+ void (*xDestructor)(void*) /* Destructor */
+){
+ DbClientData *p, **pp;
+ pp = &db->pDbData;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ pp = &p->pNext;
+ }
+ if( p ){
+ if( p->pData && p->xDestructor ) p->xDestructor(p->pData);
+ if( pData==0 ){
+ *pp = p->pNext;
+ sqlite3_free(p);
+ return SQLITE_OK;
+ }
+ }else if( pData==0 ){
+ return SQLITE_OK;
+ }else{
+ size_t n = strlen(zName);
+ p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ if( p==0 ){
+ if( pData && xDestructor ) xDestructor(pData);
+ return SQLITE_NOMEM;
+ }
+ memcpy(p->zName, zName, n+1);
+ p->pNext = db->pDbData;
+ db->pDbData = p;
+ }
+ p->pData = pData;
+ p->xDestructor = xDestructor;
+ return SQLITE_OK;
+}
+
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 48009b1454..e2fb2c1ea2 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -5325,6 +5325,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt);
*/
int sqlite3_reset(sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5879,32 +5880,32 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** SQLite will invoke the destructor function X with parameter P exactly
-** once, when the metadata is discarded.
-** SQLite is free to discard the metadata at any time, including:
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data at any time, including:
** - ^(when the corresponding function parameter changes)^, or
**
- ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
** SQL statement)^, or
@@ -5920,7 +5921,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** function implementation should not make any use of P after
** sqlite3_set_auxdata() has been called.
**
-** ^(In practice, metadata is preserved between function calls for
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -5930,10 +5931,60 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()].
*/
void *sqlite3_get_auxdata(sqlite3_context*, int N);
void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+**
+** - An out-of-memory error occurs during the call to
+** sqlite3_set_clientdata() which attempts to register pointer P.
+**
- A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+**
- The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closingi process.
+**
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is (currently) no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+*/
+void *sqlite3_get_clientdata(sqlite3*,const char*);
+int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index c2a9f855a7..785576f9c4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1256,6 +1256,7 @@ typedef struct Column Column;
typedef struct Cte Cte;
typedef struct CteUse CteUse;
typedef struct Db Db;
+typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer;
typedef struct Schema Schema;
typedef struct Expr Expr;
@@ -1734,6 +1735,7 @@ struct sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ DbClientData *pDbData; /* sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -4341,6 +4343,16 @@ struct CteUse {
};
+/* Client data associated with sqlite3_set_clientdata() and
+** sqlite3_get_clientdata().
+*/
+struct DbClientData {
+ DbClientData *pNext; /* Next in a linked list */
+ void *pData; /* The data */
+ void (*xDestructor)(void*); /* Destructor. Might be NULL */
+ char zName[1]; /* Name of this client data. MUST BE LAST */
+};
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
From adf54de51e502f5dde1fac9093c8f96586431ea0 Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 30 Aug 2023 15:42:41 +0000
Subject: [PATCH 2/9] Fix to the sqlite3_get_clientdata() interface.
FossilOrigin-Name: 937cd1762b36d48d9e7bafe42e99e524c9b5528d39f64521bce2f81d9c887db8
---
manifest | 15 ++++++---------
manifest.uuid | 2 +-
src/main.c | 2 +-
3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/manifest b/manifest
index e4e672b2aa..04595f622c 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C New\sexperimental\sAPI\sfor\sattaching\sclient\sdata\sto\sa\sdatabase\sconnection.
-D 2023-08-30T15:20:15.256
+C Fix\sto\sthe\ssqlite3_get_clientdata()\sinterface.
+D 2023-08-30T15:42:41.455
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 5c28d8b05896007a820fb1f4b9089c8e237813bf51f7de2ebc7ce88cb0f0b2ba
+F src/main.c 6afb7db21660e10c7ef111eea292db7ec32358f0a214c630086b2b92f369bfd5
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -2115,11 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 273d3b05f630d399d42914e95c416b107b4746bbef129cfba9d00fd921666261
-R ea42982c5b96fe2a959e6a802572e9d0
-T *branch * db-client-data
-T *sym-db-client-data *
-T -sym-trunk *
+P d542837fdb42ebe810fc99225860d2cc7e6dd829a635bde820a09beff6bcb481
+R dc814b298c183eac18597d205967002d
U drh
-Z da4f47e3406f7c1072eed31bdeabf988
+Z 37a0b7a018784c96d3357e0f5c4d5e5a
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 0cd4c66fa4..3159b5190d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-d542837fdb42ebe810fc99225860d2cc7e6dd829a635bde820a09beff6bcb481
\ No newline at end of file
+937cd1762b36d48d9e7bafe42e99e524c9b5528d39f64521bce2f81d9c887db8
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 994d82ed97..fb83fcfe6b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3724,7 +3724,7 @@ int sqlite3_collation_needed16(
void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
DbClientData *p;
for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){}
- return p;
+ return p ? p->pData : 0;
}
/*
From a5af4a6614ca799e3a1726e48959d5cba0c760a2 Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 30 Aug 2023 17:14:12 +0000
Subject: [PATCH 3/9] Remove an unreachable branch, and improve documentation
of sqlite3_set_clientdata().
FossilOrigin-Name: 565c68adee64b6c838f2fcb162485b6cfe9a976adb79de4370be98fcd4af2baf
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/main.c | 2 +-
src/sqlite.h.in | 2 ++
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/manifest b/manifest
index 04595f622c..a603830c4d 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sto\sthe\ssqlite3_get_clientdata()\sinterface.
-D 2023-08-30T15:42:41.455
+C Remove\san\sunreachable\sbranch,\sand\simprove\sdocumentation\sof\nsqlite3_set_clientdata().
+D 2023-08-30T17:14:12.141
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 6afb7db21660e10c7ef111eea292db7ec32358f0a214c630086b2b92f369bfd5
+F src/main.c 42672e9540b67a6e7369445cc36bba865f9d6e0536b5e7a23233ae6d1731f809
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -707,7 +707,7 @@ F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 5f545a2c8702d4d3430bbb188cfec47d6c122d899061ef00cbe56af14591c574
F src/shell.c.in 2f9be25294b68b07e7e81f0adcec4475aba6011b64f160e414efe226910c4d7b
-F src/sqlite.h.in 9f1ae109025327841ecd4f1c7fbe5550a59959ccea444e4d6e388ee5d4135602
+F src/sqlite.h.in 7dbea32976fb18740214edc314253c902e127dac7645a705e566644ed4aa5ef5
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
F src/sqliteInt.h 985a09af9a8ce7862318ff77550b9b172e684b5a10e55dd96796e08e48f6dbca
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P d542837fdb42ebe810fc99225860d2cc7e6dd829a635bde820a09beff6bcb481
-R dc814b298c183eac18597d205967002d
+P 937cd1762b36d48d9e7bafe42e99e524c9b5528d39f64521bce2f81d9c887db8
+R 41efca5fe12b212203aeac4a8130ce7f
U drh
-Z 37a0b7a018784c96d3357e0f5c4d5e5a
+Z a5ff41f13a2cbd8967a9da47012a6601
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 3159b5190d..534c3fc7aa 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-937cd1762b36d48d9e7bafe42e99e524c9b5528d39f64521bce2f81d9c887db8
\ No newline at end of file
+565c68adee64b6c838f2fcb162485b6cfe9a976adb79de4370be98fcd4af2baf
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index fb83fcfe6b..9f60ceebef 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3754,7 +3754,7 @@ int sqlite3_set_clientdata(
size_t n = strlen(zName);
p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
if( p==0 ){
- if( pData && xDestructor ) xDestructor(pData);
+ if( xDestructor ) xDestructor(pData);
return SQLITE_NOMEM;
}
memcpy(p->zName, zName, n+1);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index e2fb2c1ea2..dd1685db89 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -5982,6 +5982,8 @@ void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
**
** Database connection client data is only available for SQLite
** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()].
*/
void *sqlite3_get_clientdata(sqlite3*,const char*);
int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
From d25d938877b675a7cf8ded0948ae814b1ae026d7 Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 30 Aug 2023 17:41:55 +0000
Subject: [PATCH 4/9] Remove another unreachable branch in the
sqlite3_set_clientdata() logic.
FossilOrigin-Name: 57e31e6b10b2aa68b6039914d191819bae0aa60999a99d5ef23ca18128b72e0e
---
manifest | 12 ++++++------
manifest.uuid | 2 +-
src/main.c | 3 ++-
3 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/manifest b/manifest
index a603830c4d..9c846bbc47 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\san\sunreachable\sbranch,\sand\simprove\sdocumentation\sof\nsqlite3_set_clientdata().
-D 2023-08-30T17:14:12.141
+C Remove\sanother\sunreachable\sbranch\sin\sthe\ssqlite3_set_clientdata()\slogic.
+D 2023-08-30T17:41:55.821
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 42672e9540b67a6e7369445cc36bba865f9d6e0536b5e7a23233ae6d1731f809
+F src/main.c 3eb8c45e05829649bb15aea10cd04cbc1a116438e6a129de025b70dba73b922a
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 937cd1762b36d48d9e7bafe42e99e524c9b5528d39f64521bce2f81d9c887db8
-R 41efca5fe12b212203aeac4a8130ce7f
+P 565c68adee64b6c838f2fcb162485b6cfe9a976adb79de4370be98fcd4af2baf
+R c44620e6fdc8795cc96b9dcf7aa093f2
U drh
-Z a5ff41f13a2cbd8967a9da47012a6601
+Z ba5cdcdbc9c47766f3528cc96f85a22f
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 534c3fc7aa..99a60a7742 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-565c68adee64b6c838f2fcb162485b6cfe9a976adb79de4370be98fcd4af2baf
\ No newline at end of file
+57e31e6b10b2aa68b6039914d191819bae0aa60999a99d5ef23ca18128b72e0e
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 9f60ceebef..257b9b7600 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3742,7 +3742,8 @@ int sqlite3_set_clientdata(
pp = &p->pNext;
}
if( p ){
- if( p->pData && p->xDestructor ) p->xDestructor(p->pData);
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
if( pData==0 ){
*pp = p->pNext;
sqlite3_free(p);
From 7fc4223411b8a26279a8b29452f1307e7ec4d736 Mon Sep 17 00:00:00 2001
From: stephan
Date: Wed, 30 Aug 2023 18:45:42 +0000
Subject: [PATCH 5/9] Replace JNI's per-db-instance state tracking with the new
sqlite3_set/get_clientdata().
FossilOrigin-Name: e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e
---
ext/jni/src/c/sqlite3-jni.c | 103 +++++++++++-------------------------
manifest | 14 ++---
manifest.uuid | 2 +-
3 files changed, 40 insertions(+), 79 deletions(-)
diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c
index b426a26acc..20bc5cc986 100644
--- a/ext/jni/src/c/sqlite3-jni.c
+++ b/ext/jni/src/c/sqlite3-jni.c
@@ -447,8 +447,7 @@ struct S3JniDb {
#ifdef SQLITE_ENABLE_FTS5
jobject jFtsApi /* global ref to s3jni_fts5_api_from_db() */;
#endif
- S3JniDb * pNext /* Next entry in SJG.perDb.aFree or SJG.perDb.aHead */;
- S3JniDb * pPrev /* Previous entry in SJG.perDb.aFree or SJG.perDb.aHead */;
+ S3JniDb * pNext /* Next entry in SJG.perDb.aFree */;
};
/*
@@ -579,7 +578,6 @@ struct S3JniGlobalType {
** client-defined state to db handles there.
*/
struct {
- S3JniDb * aHead /* Linked list of in-use instances */;
S3JniDb * aFree /* Linked list of free instances */;
sqlite3_mutex * mutex /* mutex for aHead and aFree */;
void const * locker /* perDb mutex is held on this object's
@@ -1225,20 +1223,10 @@ static void S3JniDb_clear(JNIEnv * const env, S3JniDb * const s){
*/
static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
assert( s );
+ S3JniMutex_S3JniDb_assertLocker;
if( s ){
- S3JniMutex_S3JniDb_assertLocker;
- assert(s->pPrev != s);
- assert(s->pNext != s);
- assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
- if(s->pNext) s->pNext->pPrev = s->pPrev;
- if(s->pPrev) s->pPrev->pNext = s->pNext;
- else if(SJG.perDb.aHead == s){
- assert(!s->pPrev);
- SJG.perDb.aHead = s->pNext;
- }
S3JniDb_clear(env, s);
s->pNext = SJG.perDb.aFree;
- if(s->pNext) s->pNext->pPrev = s;
SJG.perDb.aFree = s;
}
}
@@ -1448,40 +1436,27 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, jobject jDb){
if( SJG.perDb.aFree ){
rv = SJG.perDb.aFree;
SJG.perDb.aFree = rv->pNext;
- assert(rv->pNext != rv);
- assert(!rv->pPrev);
- if( rv->pNext ){
- assert(rv->pNext->pPrev == rv);
- rv->pNext->pPrev = 0;
- rv->pNext = 0;
- }
+ rv->pNext = 0;
s3jni_incr( &SJG.metrics.nPdbRecycled );
}else{
rv = s3jni_malloc( sizeof(S3JniDb));
if( rv ){
- memset(rv, 0, sizeof(S3JniDb));
s3jni_incr( &SJG.metrics.nPdbAlloc );
}
}
if( rv ){
- rv->pNext = SJG.perDb.aHead;
- SJG.perDb.aHead = rv;
- if( rv->pNext ){
- assert(!rv->pNext->pPrev);
- rv->pNext->pPrev = rv;
- }
+ memset(rv, 0, sizeof(S3JniDb));
rv->jDb = S3JniRefGlobal(jDb);
}
S3JniMutex_S3JniDb_leave;
return rv;
}
+#define S3JniDb_clientdata_key "S3JniDb"
+
/* Short-lived code consolidator. */
-#define S3JniDb_search \
- s = SJG.perDb.aHead; \
- for( ; pDb && s; s = s->pNext){ \
- if( s->pDb == pDb ) break; \
- }
+#define S3JniDb_search \
+ s = pDb ? sqlite3_get_clientdata(pDb, S3JniDb_clientdata_key) : 0
/*
** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3
@@ -1511,10 +1486,20 @@ static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
if( jDb ) pDb = PtrGet_sqlite3(jDb);
S3JniDb_search;
return s;
-
}
#define S3JniDb_from_java_unlocked(JDB) S3JniDb__from_java_unlocked(env, (JDB))
+/*
+** S3JniDb finalizer for use with sqlite3_set_clientdata().
+*/
+static void S3JniDb_xDestroy(void *p){
+ S3JniDb * ps = p;
+ S3JniDeclLocal_env;
+
+ assert( !ps->pNext );
+ S3JniDb_set_aside(ps);
+}
+
/*
** Returns the S3JniDb object for the sqlite3 object, or NULL if pDb
** is NULL, or no matching entry
@@ -2132,9 +2117,15 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
jc->pdbOpening = 0;
assert( !ps->pDb && "it's still being opened" );
assert( ps->jDb );
- ps->pDb = pDb;
+ rc = sqlite3_set_clientdata(pDb, S3JniDb_clientdata_key,
+ ps, 0/* we'll re-set this after open()
+ completes. */);
+ if( rc ){
+ return rc;
+ }
NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb)
/* As of here, the Java/C connection is complete */;
+ ps->pDb = pDb;
for( i = 0; go && 0==rc; ++i ){
S3JniAutoExtension ax = {0,0}
/* We need a copy of the auto-extension object, with our own
@@ -2447,8 +2438,6 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
/* Wrapper for sqlite3_close(_v2)(). */
static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
int rc = 0;
-//#define CLOSE_DB_LOCKED /* An experiment */
-#ifndef CLOSE_DB_LOCKED
S3JniDb * const ps = S3JniDb_from_java(jDb);
assert(version == 1 || version == 2);
@@ -2458,38 +2447,8 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
: (jint)sqlite3_close_v2(ps->pDb);
if( 0==rc ){
NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
- S3JniDb_set_aside(ps)
- /* MUST come after close() because of ps->trace. */;
}
}
-#else
- /* This impl leads to an assertion in sqlite3_close[_v2]()
-
- pthreadMutexEnter: Assertion `p->id==SQLITE_MUTEX_RECURSIVE
- || pthreadMutexNotheld(p)' failed.
-
- For reasons not yet fully understood.
- */
- assert(version == 1 || version == 2);
- if( 0!=jDb ){
- S3JniDb * ps;
- S3JniMutex_S3JniDb_enter;
- ps = S3JniDb_from_java_unlocked(jDb);
- if( ps && ps->pDb ){
- rc = 1==version
- ? (jint)sqlite3_close(ps->pDb)
- : (jint)sqlite3_close_v2(ps->pDb);
- if( 0==rc ){
- S3JniDb_set_aside_unlocked(ps)
- /* MUST come after close() because of ps->hooks.trace. */;
- NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
- }
- }else{
- /* ps is from S3Global.perDb.aFree. */
- }
- S3JniMutex_S3JniDb_leave;
- }
-#endif
return (jint)rc;
}
@@ -3307,23 +3266,26 @@ end:
static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc,
S3JniDb * ps, sqlite3 **ppDb,
jobject jOut, int theRc){
+ int rc = 0;
jc->pdbOpening = 0;
if( *ppDb ){
assert(ps->jDb);
if( 0==ps->pDb ){
ps->pDb = *ppDb;
- NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb)
- /* As of here, the Java/C connection is complete */;
+ NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb);
}else{
assert( ps->pDb==*ppDb
&& "Set up via s3jni_run_java_auto_extensions()" );
}
+ rc = sqlite3_set_clientdata(ps->pDb, S3JniDb_clientdata_key,
+ ps, S3JniDb_xDestroy);
+ /* As of here, the Java/C connection is complete */
}else{
S3JniDb_set_aside(ps);
ps = 0;
}
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
- return theRc;
+ return theRc ? theRc : rc;
}
S3JniApi(sqlite3_open(),jint,1open)(
@@ -4040,7 +4002,6 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
while( S3JniGlobal.perDb.aFree ){
S3JniDb * const d = S3JniGlobal.perDb.aFree;
S3JniGlobal.perDb.aFree = d->pNext;
- d->pNext = 0;
S3JniDb_clear(env, d);
sqlite3_free(d);
}
diff --git a/manifest b/manifest
index 9c846bbc47..9d22529099 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sanother\sunreachable\sbranch\sin\sthe\ssqlite3_set_clientdata()\slogic.
-D 2023-08-30T17:41:55.821
+C Replace\sJNI's\sper-db-instance\sstate\stracking\swith\sthe\snew\ssqlite3_set/get_clientdata().
+D 2023-08-30T18:45:42.722
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -237,7 +237,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-F ext/jni/src/c/sqlite3-jni.c 3d80af6bfa4af38dc50a919f97219a481410de1f6f885644b2f97cd64ab9b863
+F ext/jni/src/c/sqlite3-jni.c aaec2851258a7d9c9907d8e864a17e055676ec0adb64f335d979fa19674a0cab
F ext/jni/src/c/sqlite3-jni.h 12e1a5ef5ee1795dc22577c285b4518dfd8aa4af45757f6cb81a555d967bf201
F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 565c68adee64b6c838f2fcb162485b6cfe9a976adb79de4370be98fcd4af2baf
-R c44620e6fdc8795cc96b9dcf7aa093f2
-U drh
-Z ba5cdcdbc9c47766f3528cc96f85a22f
+P 57e31e6b10b2aa68b6039914d191819bae0aa60999a99d5ef23ca18128b72e0e
+R 936a89e0748a165d8e043fd6221f1b2f
+U stephan
+Z 84bdefd82082ec3e33e8b63200701207
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 99a60a7742..28927e9512 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-57e31e6b10b2aa68b6039914d191819bae0aa60999a99d5ef23ca18128b72e0e
\ No newline at end of file
+e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e
\ No newline at end of file
From 3823208d5b199eeb101a28969b189bb9a42c447f Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 30 Aug 2023 18:51:26 +0000
Subject: [PATCH 6/9] Use mutexes to make sqlite3_set_clientdata() and
sqlite3_get_clientdata() threadsafe.
FossilOrigin-Name: 443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/main.c | 17 +++++++++++++++--
3 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/manifest b/manifest
index 9d22529099..0b380a8a0e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Replace\sJNI's\sper-db-instance\sstate\stracking\swith\sthe\snew\ssqlite3_set/get_clientdata().
-D 2023-08-30T18:45:42.722
+C Use\smutexes\sto\smake\ssqlite3_set_clientdata()\sand\ssqlite3_get_clientdata()\nthreadsafe.
+D 2023-08-30T18:51:26.770
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 3eb8c45e05829649bb15aea10cd04cbc1a116438e6a129de025b70dba73b922a
+F src/main.c 2adfb1973ee495977f8c75d6590aae9882161d5f8749b46621299656a2df0cc6
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 57e31e6b10b2aa68b6039914d191819bae0aa60999a99d5ef23ca18128b72e0e
-R 936a89e0748a165d8e043fd6221f1b2f
-U stephan
-Z 84bdefd82082ec3e33e8b63200701207
+P e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e
+R 3f04e2f3da46f99baea85816871f54e6
+U drh
+Z 4a72dec53887e83eac398e1a9fd59cf2
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 28927e9512..14a82559d3 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e
\ No newline at end of file
+443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 257b9b7600..6525fc0d71 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3723,8 +3723,16 @@ int sqlite3_collation_needed16(
*/
void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
DbClientData *p;
- for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){}
- return p ? p->pData : 0;
+ sqlite3_mutex_enter(db->mutex);
+ for(p=db->pDbData; p; p=p->pNext){
+ if( strcmp(p->zName, zName)==0 ){
+ void *pResult = p->pData;
+ sqlite3_mutex_leave(db->mutex);
+ return pResult;
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return 0;
}
/*
@@ -3737,6 +3745,7 @@ int sqlite3_set_clientdata(
void (*xDestructor)(void*) /* Destructor */
){
DbClientData *p, **pp;
+ sqlite3_mutex_enter(db->mutex);
pp = &db->pDbData;
for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
pp = &p->pNext;
@@ -3747,15 +3756,18 @@ int sqlite3_set_clientdata(
if( pData==0 ){
*pp = p->pNext;
sqlite3_free(p);
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
}else if( pData==0 ){
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}else{
size_t n = strlen(zName);
p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
if( p==0 ){
if( xDestructor ) xDestructor(pData);
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_NOMEM;
}
memcpy(p->zName, zName, n+1);
@@ -3764,6 +3776,7 @@ int sqlite3_set_clientdata(
}
p->pData = pData;
p->xDestructor = xDestructor;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
From 21d4f0cc7bccb44c674dcc148850e9fa5077b9d6 Mon Sep 17 00:00:00 2001
From: stephan
Date: Sat, 2 Sep 2023 08:04:56 +0000
Subject: [PATCH 7/9] Optimize sqlite3_get/set_clientdata() for the presumably
common case of a static string pointer.
FossilOrigin-Name: 84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/main.c | 6 ++++--
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/manifest b/manifest
index 0b380a8a0e..9d593d485e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Use\smutexes\sto\smake\ssqlite3_set_clientdata()\sand\ssqlite3_get_clientdata()\nthreadsafe.
-D 2023-08-30T18:51:26.770
+C Optimize\ssqlite3_get/set_clientdata()\sfor\sthe\spresumably\scommon\scase\sof\sa\sstatic\sstring\spointer.
+D 2023-09-02T08:04:56.497
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 2adfb1973ee495977f8c75d6590aae9882161d5f8749b46621299656a2df0cc6
+F src/main.c 42a55d977879a6968d4b1609424b318f991bd0375e48ac42d8f742f41e243468
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e7c11d34ee2eebdca4d9db1496bbb4152e4c62745c083ad5e0337733e8d1254e
-R 3f04e2f3da46f99baea85816871f54e6
-U drh
-Z 4a72dec53887e83eac398e1a9fd59cf2
+P 443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
+R 296f08550097c4b7507cdcac1545a235
+U stephan
+Z 18c0164302708bbf7ef418d7eac59c3e
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 14a82559d3..9e693a411a 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
\ No newline at end of file
+84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 6525fc0d71..7cc15869be 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3725,7 +3725,7 @@ void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
DbClientData *p;
sqlite3_mutex_enter(db->mutex);
for(p=db->pDbData; p; p=p->pNext){
- if( strcmp(p->zName, zName)==0 ){
+ if( zName==p->zName || strcmp(p->zName, zName)==0 ){
void *pResult = p->pData;
sqlite3_mutex_leave(db->mutex);
return pResult;
@@ -3747,7 +3747,9 @@ int sqlite3_set_clientdata(
DbClientData *p, **pp;
sqlite3_mutex_enter(db->mutex);
pp = &db->pDbData;
- for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ for(p=db->pDbData;
+ p && (zName!=p->zName && strcmp(p->zName,zName));
+ p=p->pNext){
pp = &p->pNext;
}
if( p ){
From 93b461ff001f777b6367773c14744ec8f1ba3cca Mon Sep 17 00:00:00 2001
From: drh <>
Date: Wed, 6 Sep 2023 17:07:53 +0000
Subject: [PATCH 8/9] Add documentation to sqlite3_get/set_clientdata() to make
it clear that these are security-sensitive interfaces that should not be
exposed to potential attackers.
FossilOrigin-Name: 2837061d66672a0a73c3fd2ff35ce0e1a66ee6d5365be25d4cc0ccba170c3665
---
manifest | 14 +++++++-------
manifest.uuid | 2 +-
src/sqlite.h.in | 7 ++++++-
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/manifest b/manifest
index 9d593d485e..588e3f5615 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Optimize\ssqlite3_get/set_clientdata()\sfor\sthe\spresumably\scommon\scase\sof\sa\sstatic\sstring\spointer.
-D 2023-09-02T08:04:56.497
+C Add\sdocumentation\sto\ssqlite3_get/set_clientdata()\sto\smake\sit\sclear\sthat\sthese\nare\ssecurity-sensitive\sinterfaces\sthat\sshould\snot\sbe\sexposed\sto\spotential\nattackers.
+D 2023-09-06T17:07:53.343
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -707,7 +707,7 @@ F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 5f545a2c8702d4d3430bbb188cfec47d6c122d899061ef00cbe56af14591c574
F src/shell.c.in 2f9be25294b68b07e7e81f0adcec4475aba6011b64f160e414efe226910c4d7b
-F src/sqlite.h.in 7dbea32976fb18740214edc314253c902e127dac7645a705e566644ed4aa5ef5
+F src/sqlite.h.in 1683783c7639ac73378d1a705be6faf115c374c6c3c102412642d43c9eaed74d
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
F src/sqliteInt.h 985a09af9a8ce7862318ff77550b9b172e684b5a10e55dd96796e08e48f6dbca
@@ -2115,8 +2115,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 443ea20ddb0f3bf5d77ef59cd4678f0e32d7da328002bb44d6fc080a53a37e29
-R 296f08550097c4b7507cdcac1545a235
-U stephan
-Z 18c0164302708bbf7ef418d7eac59c3e
+P 84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
+R ba107aa1186f8a45aa47c9a536cfe51b
+U drh
+Z 0b41bcf28b9ce0b44f7baeffddd8bf46
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 9e693a411a..ce51826a55 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
\ No newline at end of file
+2837061d66672a0a73c3fd2ff35ce0e1a66ee6d5365be25d4cc0ccba170c3665
\ No newline at end of file
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index dd1685db89..43f45555e0 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -5975,11 +5975,16 @@ void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
** Applications and wrapper libraries are discouraged from using more than
** one client data name each.
**
-** There is (currently) no way to enumerate the client data pointers
+** There is no way to enumerate the client data pointers
** associated with a database connection. The N parameter can be thought
** of as a secret key such that only code that knows the secret key is able
** to access the associated data.
**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
** Database connection client data is only available for SQLite
** version 3.44.0 ([dateof:3.44.0]) and later.
**
From 7fa8d65539ae661fe9f4ba59a49050d4101cfa9e Mon Sep 17 00:00:00 2001
From: stephan
Date: Sun, 10 Sep 2023 10:56:28 +0000
Subject: [PATCH 9/9] Roll back [84e38341aeab] because a direct pointer
comparison is ill-advised when the client-data string is dynamically
allocated.
FossilOrigin-Name: 7b884832b71c23e62ba3c0d53f7c89199734c351f909d84ac19ac18c7ddccbd8
---
manifest | 15 ++++++++-------
manifest.uuid | 2 +-
src/main.c | 6 ++----
3 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/manifest b/manifest
index 588e3f5615..e0c9581f0c 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sdocumentation\sto\ssqlite3_get/set_clientdata()\sto\smake\sit\sclear\sthat\sthese\nare\ssecurity-sensitive\sinterfaces\sthat\sshould\snot\sbe\sexposed\sto\spotential\nattackers.
-D 2023-09-06T17:07:53.343
+C Roll\sback\s[84e38341aeab]\sbecause\sa\sdirect\spointer\scomparison\sis\sill-advised\swhen\sthe\sclient-data\sstring\sis\sdynamically\sallocated.
+D 2023-09-10T10:56:28.783
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -668,7 +668,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 42a55d977879a6968d4b1609424b318f991bd0375e48ac42d8f742f41e243468
+F src/main.c 2adfb1973ee495977f8c75d6590aae9882161d5f8749b46621299656a2df0cc6
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -2115,8 +2115,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
-R ba107aa1186f8a45aa47c9a536cfe51b
-U drh
-Z 0b41bcf28b9ce0b44f7baeffddd8bf46
+P 2837061d66672a0a73c3fd2ff35ce0e1a66ee6d5365be25d4cc0ccba170c3665
+Q -84e38341aeab4fd51690e8536d0101d00e3fb11cc50ebcff05ed219c98328872
+R 02e3e46c1cccd00057fe7df753345750
+U stephan
+Z 61ef124a3f5005010110573ed4089eb8
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index ce51826a55..52007cf528 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-2837061d66672a0a73c3fd2ff35ce0e1a66ee6d5365be25d4cc0ccba170c3665
\ No newline at end of file
+7b884832b71c23e62ba3c0d53f7c89199734c351f909d84ac19ac18c7ddccbd8
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 7cc15869be..6525fc0d71 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3725,7 +3725,7 @@ void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
DbClientData *p;
sqlite3_mutex_enter(db->mutex);
for(p=db->pDbData; p; p=p->pNext){
- if( zName==p->zName || strcmp(p->zName, zName)==0 ){
+ if( strcmp(p->zName, zName)==0 ){
void *pResult = p->pData;
sqlite3_mutex_leave(db->mutex);
return pResult;
@@ -3747,9 +3747,7 @@ int sqlite3_set_clientdata(
DbClientData *p, **pp;
sqlite3_mutex_enter(db->mutex);
pp = &db->pDbData;
- for(p=db->pDbData;
- p && (zName!=p->zName && strcmp(p->zName,zName));
- p=p->pNext){
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
pp = &p->pNext;
}
if( p ){