aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2007-05-07 09:32:45 +0000
committerdanielk1977 <danielk1977@noemail.net>2007-05-07 09:32:45 +0000
commita9808b31a8c3ebd8fecc7c63afdec7519ccdafd1 (patch)
treebc3a302d4075e3b9925f115ddfc4b0acf5552a64 /src
parenta58906a8dd74d751c4c9609f828f9043c1a983b1 (diff)
downloadsqlite-a9808b31a8c3ebd8fecc7c63afdec7519ccdafd1.tar.gz
sqlite-a9808b31a8c3ebd8fecc7c63afdec7519ccdafd1.zip
Add the experimental create_collation_x() api. (CVS 3934)
FossilOrigin-Name: ff49d48f2f025898a0f4ace1fc227e1d367ea89f
Diffstat (limited to 'src')
-rw-r--r--src/callback.c3
-rw-r--r--src/main.c63
-rw-r--r--src/sqlite.h.in14
-rw-r--r--src/sqliteInt.h11
-rw-r--r--src/test1.c106
5 files changed, 178 insertions, 19 deletions
diff --git a/src/callback.c b/src/callback.c
index 87f5b2472..f3d418808 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
-** $Id: callback.c,v 1.17 2007/04/16 15:06:25 danielk1977 Exp $
+** $Id: callback.c,v 1.18 2007/05/07 09:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -63,6 +63,7 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0);
if( pColl2->xCmp!=0 ){
memcpy(pColl, pColl2, sizeof(CollSeq));
+ pColl->xDel = 0; /* Do not copy the destructor */
return SQLITE_OK;
}
}
diff --git a/src/main.c b/src/main.c
index 38aa70bb1..bd72bdd97 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.371 2007/05/06 16:04:12 danielk1977 Exp $
+** $Id: main.c,v 1.372 2007/05/07 09:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -182,6 +182,12 @@ int sqlite3_close(sqlite3 *db){
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
+ /* Invoke any destructors registered for collation sequence user data. */
+ for(j=0; j<3; j++){
+ if( pColl[j].xDel ){
+ pColl[j].xDel(pColl[j].pUser);
+ }
+ }
sqliteFree(pColl);
}
sqlite3HashClear(&db->aCollSeq);
@@ -825,7 +831,8 @@ static int createCollation(
const char *zName,
int enc,
void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
){
CollSeq *pColl;
int enc2;
@@ -860,12 +867,33 @@ static int createCollation(
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
+
+ /* If collation sequence pColl was created directly by a call to
+ ** sqlite3_create_collation, and not generated by synthCollSeq(),
+ ** then any copies made by synthCollSeq() need to be invalidated.
+ ** Also, collation destructor - CollSeq.xDel() - function may need
+ ** to be called.
+ */
+ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
+ CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, strlen(zName));
+ int j;
+ for(j=0; j<3; j++){
+ CollSeq *p = &aColl[j];
+ if( p->enc==pColl->enc ){
+ if( p->xDel ){
+ p->xDel(p->pUser);
+ }
+ p->xCmp = 0;
+ }
+ }
+ }
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1);
if( pColl ){
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
+ pColl->xDel = xDel;
pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
}
sqlite3Error(db, SQLITE_OK, 0);
@@ -915,9 +943,9 @@ static int openDatabase(
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
*/
- if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
+ if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0) ||
(db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
){
assert( sqlite3MallocFailed() );
@@ -926,7 +954,7 @@ static int openDatabase(
}
/* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
@@ -986,7 +1014,7 @@ static int openDatabase(
#endif
#ifdef SQLITE_ENABLE_ICU
- {
+ if( !sqlite3MallocFailed() ){
extern int sqlite3IcuInit(sqlite3*);
sqlite3IcuInit(db);
}
@@ -1106,7 +1134,24 @@ int sqlite3_create_collation(
){
int rc;
assert( !sqlite3MallocFailed() );
- rc = createCollation(db, zName, enc, pCtx, xCompare);
+ rc = createCollation(db, zName, enc, pCtx, xCompare, 0);
+ return sqlite3ApiExit(db, rc);
+}
+
+/*
+** Register a new collation sequence with the database handle db.
+*/
+int sqlite3_create_collation_x(
+ sqlite3* db,
+ const char *zName,
+ int enc,
+ void* pCtx,
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
+){
+ int rc;
+ assert( !sqlite3MallocFailed() );
+ rc = createCollation(db, zName, enc, pCtx, xCompare, xDel);
return sqlite3ApiExit(db, rc);
}
@@ -1126,7 +1171,7 @@ int sqlite3_create_collation16(
assert( !sqlite3MallocFailed() );
zName8 = sqlite3utf16to8(zName, -1);
if( zName8 ){
- rc = createCollation(db, zName8, enc, pCtx, xCompare);
+ rc = createCollation(db, zName8, enc, pCtx, xCompare, 0);
sqliteFree(zName8);
}
return sqlite3ApiExit(db, rc);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 4af11e26c..f84128c55 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.204 2007/05/03 16:31:26 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.205 2007/05/07 09:32:45 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -1280,6 +1280,18 @@ int sqlite3_create_collation16(
);
/*
+****** EXPERIMENTAL - subject to change without notice **************
+*/
+int sqlite3_create_collation_x(
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
+ void*,
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
+);
+
+/*
** To avoid having to register all collation sequences before a database
** can be used, a single callback function may be registered with the
** database handle to be called whenever an undefined collation sequence is
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index c5917c643..374f1ebe1 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.557 2007/05/05 11:48:54 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.558 2007/05/07 09:32:45 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -646,11 +646,12 @@ struct Column {
** collating sequence may not be read or written.
*/
struct CollSeq {
- char *zName; /* Name of the collating sequence, UTF-8 encoded */
- u8 enc; /* Text encoding handled by xCmp() */
- u8 type; /* One of the SQLITE_COLL_... values below */
- void *pUser; /* First argument to xCmp() */
+ char *zName; /* Name of the collating sequence, UTF-8 encoded */
+ u8 enc; /* Text encoding handled by xCmp() */
+ u8 type; /* One of the SQLITE_COLL_... values below */
+ void *pUser; /* First argument to xCmp() */
int (*xCmp)(void*,int, const void*, int, const void*);
+ void (*xDel)(void*); /* Destructor for pUser */
};
/*
diff --git a/src/test1.c b/src/test1.c
index e4221b110..479390dea 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -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.247 2007/05/06 16:04:12 danielk1977 Exp $
+** $Id: test1.c,v 1.248 2007/05/07 09:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1508,6 +1508,18 @@ static int test_table_column_metadata(
/*
** sqlite3_blob_read CHANNEL OFFSET N
+**
+** This command is used to test the sqlite3_blob_read() in ways that
+** the Tcl channel interface does not. The first argument should
+** be the name of a valid channel created by the [incrblob] method
+** of a database handle. This function calls sqlite3_blob_read()
+** to read N bytes from offset OFFSET from the underlying SQLite
+** blob handle.
+**
+** On success, a byte-array object containing the read data is
+** returned. On failure, the interpreter result is set to the
+** text representation of the returned error code (i.e. "SQLITE_NOMEM")
+** and a Tcl exception is thrown.
*/
static int test_blob_read(
ClientData clientData, /* Not used */
@@ -1555,6 +1567,17 @@ static int test_blob_read(
/*
** sqlite3_blob_write CHANNEL OFFSET DATA
+**
+** This command is used to test the sqlite3_blob_write() in ways that
+** the Tcl channel interface does not. The first argument should
+** be the name of a valid channel created by the [incrblob] method
+** of a database handle. This function calls sqlite3_blob_write()
+** to write the DATA byte-array to the underlying SQLite blob handle.
+** at offset OFFSET.
+**
+** On success, an empty string is returned. On failure, the interpreter
+** result is set to the text representation of the returned error code
+** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
*/
static int test_blob_write(
ClientData clientData, /* Not used */
@@ -1599,6 +1622,82 @@ static int test_blob_write(
#endif
/*
+** Usage: sqlite3_create_collation_x DB-HANDLE NAME CMP-PROC DEL-PROC
+**
+** This Tcl proc is used for testing the experimental
+** sqlite3_create_collation_x() interface.
+*/
+struct TestCollationX {
+ Tcl_Interp *interp;
+ Tcl_Obj *pCmp;
+ Tcl_Obj *pDel;
+};
+typedef struct TestCollationX TestCollationX;
+static void testCreateCollationDel(void *pCtx){
+ TestCollationX *p = (TestCollationX *)pCtx;
+
+ int rc = Tcl_EvalObjEx(p->interp, p->pDel, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
+ if( rc!=TCL_OK ){
+ Tcl_BackgroundError(p->interp);
+ }
+
+ Tcl_DecrRefCount(p->pCmp);
+ Tcl_DecrRefCount(p->pDel);
+ sqlite3_free((void *)p);
+}
+static int testCreateCollationCmp(
+ void *pCtx,
+ int nLeft,
+ const void *zLeft,
+ int nRight,
+ const void *zRight
+){
+ TestCollationX *p = (TestCollationX *)pCtx;
+ Tcl_Obj *pScript = Tcl_DuplicateObj(p->pCmp);
+ int iRes = 0;
+
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zLeft, nLeft));
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zRight,nRight));
+
+ if( TCL_OK!=Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL)
+ || TCL_OK!=Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iRes)
+ ){
+ Tcl_BackgroundError(p->interp);
+ }
+ Tcl_DecrRefCount(pScript);
+
+ return iRes;
+}
+static int test_create_collation_x(
+ ClientData clientData, /* Not used */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ TestCollationX *p;
+ sqlite3 *db;
+
+ if( objc!=5 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+ p = (TestCollationX *)sqlite3_malloc(sizeof(TestCollationX));
+ p->pCmp = objv[3];
+ p->pDel = objv[4];
+ p->interp = interp;
+ Tcl_IncrRefCount(p->pCmp);
+ Tcl_IncrRefCount(p->pDel);
+
+ sqlite3_create_collation_x(db, Tcl_GetString(objv[2]), SQLITE_UTF8,
+ (void *)p, testCreateCollationCmp, testCreateCollationDel
+ );
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
*/
static int test_load_extension(
@@ -4617,8 +4716,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{"sqlite3_column_origin_name16", test_stmt_utf16, sqlite3_column_origin_name16},
#endif
#endif
- { "sqlite3_global_recover", test_global_recover, 0 },
- { "working_64bit_int", working_64bit_int, 0 },
+ { "sqlite3_create_collation_x", test_create_collation_x, 0 },
+ { "sqlite3_global_recover", test_global_recover, 0 },
+ { "working_64bit_int", working_64bit_int, 0 },
/* Functions from os.h */
#ifndef SQLITE_OMIT_DISKIO