aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2020-02-18 19:49:48 +0000
committerdrh <drh@noemail.net>2020-02-18 19:49:48 +0000
commit4defdddc31c9ad128ddc80860e794616664999ef (patch)
tree190f70d7d22d8182ab909ba30329b709e65ba1c6 /src
parent0184a256e3f4cc124ef0f72a207ba430796d28a6 (diff)
downloadsqlite-4defdddc31c9ad128ddc80860e794616664999ef.tar.gz
sqlite-4defdddc31c9ad128ddc80860e794616664999ef.zip
Add the new sqlite3_create_filename() and sqlite3_free_filename() interfaces
for use by Shims. Use these interfaces inside the multiplexor. FossilOrigin-Name: 9469f36ac89e4b75d0ab25fefbeff25201992c53141da915dcaa017083cab6db
Diffstat (limited to 'src')
-rw-r--r--src/loadext.c3
-rw-r--r--src/main.c62
-rw-r--r--src/pager.c5
-rw-r--r--src/sqlite.h.in53
-rw-r--r--src/sqlite3ext.h7
-rw-r--r--src/test_multiplex.c7
6 files changed, 135 insertions, 2 deletions
diff --git a/src/loadext.c b/src/loadext.c
index 245e9b004..06297e6bb 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -474,6 +474,9 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_filename_database,
sqlite3_filename_journal,
sqlite3_filename_wal,
+ /* Version 3.32.0 and later */
+ sqlite3_create_filename,
+ sqlite3_free_filename,
};
/*
diff --git a/src/main.c b/src/main.c
index 3eccd08ea..4bfd94346 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4243,6 +4243,68 @@ static const char *databaseName(const char *zName){
}
/*
+** Append text z[] to the end of p[]. Return a pointer to the first
+** character after then zero terminator on the new text in p[].
+*/
+static char *appendText(char *p, const char *z){
+ size_t n = strlen(z);
+ memcpy(p, z, n+1);
+ return p+n+1;
+}
+
+/*
+** Allocate memory to hold names for a database, journal file, WAL file,
+** and query parameters. The pointer returned is valid for use by
+** sqlite3_filename_database() and sqlite3_uri_parameter() and related
+** functions.
+**
+** Memory layout must be compatible with that generated by the pager
+** and expected by sqlite3_uri_parameter() and databaseName().
+*/
+char *sqlite3_create_filename(
+ const char *zDatabase,
+ const char *zJournal,
+ const char *zWal,
+ int nParam,
+ const char **azParam
+){
+ sqlite3_int64 nByte;
+ int i;
+ char *pResult, *p;
+ nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10;
+ for(i=0; i<nParam*2; i++){
+ nByte += strlen(azParam[i])+1;
+ }
+ pResult = p = sqlite3_malloc64( nByte );
+ if( p==0 ) return 0;
+ memset(p, 0, 4);
+ p += 4;
+ p = appendText(p, zDatabase);
+ for(i=0; i<nParam*2; i++){
+ p = appendText(p, azParam[i]);
+ }
+ *(p++) = 0;
+ p = appendText(p, zJournal);
+ p = appendText(p, zWal);
+ *(p++) = 0;
+ *(p++) = 0;
+ assert( (sqlite3_int64)(p - pResult)==nByte );
+ return pResult + 4;
+}
+
+/*
+** Free memory obtained from sqlite3_create_filename(). It is a severe
+** error to call this routine with any parameter other than a pointer
+** previously obtained from sqlite3_create_filename() or a NULL pointer.
+*/
+void sqlite3_free_filename(char *p){
+ if( p==0 ) return;
+ p = (char*)databaseName(p);
+ sqlite3_free(p - 4);
+}
+
+
+/*
** This is a utility routine, useful to VFS implementations, that checks
** to see if a database file was a URI that contained a specific query
** parameter, and if so obtains the value of the query parameter.
diff --git a/src/pager.c b/src/pager.c
index ff62926e7..21473bf25 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -4770,6 +4770,11 @@ int sqlite3PagerOpen(
** - \0
** - WAL Path (zWALName)
** - \0
+ **
+ ** The sqlite3_create_filename() interface and the databaseFilename() utility
+ ** that is used by sqlite3_filename_database() and kin also depend on the
+ ** specific formatting and order of the various filenames, so if the format
+ ** changes here, be sure to change it there as well.
*/
pPtr = (u8 *)sqlite3MallocZero(
ROUND8(sizeof(*pPager)) + /* Pager structure */
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 0537ab69f..7b2049ae0 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -3617,6 +3617,59 @@ const char *sqlite3_filename_database(const char*);
const char *sqlite3_filename_journal(const char*);
const char *sqlite3_filename_wal(const char*);
+/*
+** CAPI3REF: Create and Destroy VFS Filenames
+**
+** These interfces are provided for use by [VFS shim] implementations and
+** are not useful outside of that context.
+**
+** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
+** database filename D with corresponding journal file J and WAL file W and
+** with N URI parameters key/values pairs in the array P. The result from
+** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
+** is safe to pass to routines like:
+** <ul>
+** <li> [sqlite3_uri_parameter()],
+** <li> [sqlite3_uri_boolean()],
+** <li> [sqlite3_uri_int64()],
+** <li> [sqlite3_uri_key()],
+** <li> [sqlite3_filename_database()],
+** <li> [sqlite3_filename_journal()], or
+** <li> [sqlite3_filename_wal()].
+** </ul>
+** If a memory allocation error occurs, sqlite3_create_filename() might
+** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
+** must be released by a corresponding call to sqlite3_free_filename(Y).
+**
+** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
+** of 2*N pointers to strings. Each pair of pointers in this array corresponds
+** to a key and value for a query parameter. The P parameter may be a NULL
+** pointer if N is zero. None of the 2*N pointers in the P array may be
+** NULL pointers and key pointers should not be empty strings.
+** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
+** be NULL pointers, though they can be empty strings.
+**
+** The sqlite3_free_filename(Y) routine releases a memory allocation
+** previously obtained from sqlite3_create_filename(). Invoking
+** sqlite3_free_filename(Y) is a NULL pointer is a harmless no-op.
+**
+** If the Y parameter to sqlite3_free_filename(Y) is anything other
+** than a NULL pointer or a pointer previously acquired from
+** sqlite3_create_filename(), then bad things such as heap
+** corruption or segfaults may occur. The value Y should be
+** used again after sqlite3_free_filename(Y) has been called. This means
+** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
+** then the corresponding [sqlite3_module.xClose() method should also be
+** invoked prior to calling sqlite3_free_filename(Y).
+*/
+char *sqlite3_create_filename(
+ const char *zDatabase,
+ const char *zJournal,
+ const char *zWal,
+ int nParam,
+ const char **azParam
+);
+void sqlite3_free_filename(char*);
/*
** CAPI3REF: Error Codes And Messages
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index bdd0a85ed..a7c76a678 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -330,6 +330,10 @@ struct sqlite3_api_routines {
const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
+ /* Version 3.32.0 and later */
+ char *(*create_filename)(const char*,const char*,const char*,
+ int,const char**);
+ void (*free_filename)(char*);
};
/*
@@ -630,6 +634,9 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
+/* Version 3.32.0 and later */
+#define sqlite3_create_filename sqlite3_api->create_filename
+#define sqlite3_free_filename sqlite3_api->free_filename
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/test_multiplex.c b/src/test_multiplex.c
index 56e78c35f..3c9aa034c 100644
--- a/src/test_multiplex.c
+++ b/src/test_multiplex.c
@@ -267,11 +267,14 @@ static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
char *z;
int n = pGroup->nName;
- pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 );
+ z = sqlite3_malloc64( n+5 );
if( z==0 ){
return SQLITE_NOMEM;
}
multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
+ pGroup->aReal[iChunk].z = sqlite3_create_filename(z,"","",0,0);
+ sqlite3_free(z);
+ if( pGroup->aReal[iChunk].z==0 ) return SQLITE_NOMEM;
}
return SQLITE_OK;
}
@@ -438,7 +441,7 @@ static void multiplexSubClose(
}
sqlite3_free(pGroup->aReal[iChunk].p);
}
- sqlite3_free(pGroup->aReal[iChunk].z);
+ sqlite3_free_filename(pGroup->aReal[iChunk].z);
memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
}