SQLite4
Check-in [e5d82c92f0]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Remove the no longer required FuncDestructor object.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e5d82c92f092f99f8968ddd77c198b0cbb298ef7
User & Date: dan 2013-06-13 16:32:32
Context
2013-06-13
20:20
Remove the encoding argument from sqlite4_create_collation(). Pass sqlite4_value objects to the collation sequence callbacks instead. check-in: 7f314c9a71 user: dan tags: trunk
16:32
Remove the no longer required FuncDestructor object. check-in: e5d82c92f0 user: dan tags: trunk
15:24
Remove the 'encoding' argument from sqlite4_create_function(). check-in: f88d080127 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/main.c.

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340


341
342
343
344
345
346
347
...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
...
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
  }
  db->nSavepoint = 0;
  db->nStatement = 0;
}

/*
** Invoke the destructor function associated with FuncDef p, if any. Except,
** if this is not the last copy of the function, do not invoke it. Multiple
** copies of a single function are created when create_function() is called
** with SQLITE4_ANY as the encoding.
*/
static void functionDestroy(sqlite4 *db, FuncDef *p){
  FuncDestructor *pDestructor = p->pDestructor;
  if( pDestructor ){
    pDestructor->nRef--;
    if( pDestructor->nRef==0 ){
      pDestructor->xDestroy(pDestructor->pUserData);
      sqlite4DbFree(db, pDestructor);
    }


  }
}

/*
** Close an existing SQLite database
*/
int sqlite4_close(sqlite4 *db, unsigned int flags){
................................................................................
  sqlite4 *db,
  const char *zFunctionName,
  int nArg,
  void *pUserData,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*),
  FuncDestructor *pDestructor
){
  FuncDef *p;
  int nName;

  assert( sqlite4_mutex_held(db->mutex) );
  if( zFunctionName==0 ||
      (xFunc && (xFinal || xStep)) || 
................................................................................
    return SQLITE4_NOMEM;
  }

  /* If an older version of the function with a configured destructor is
  ** being replaced invoke the destructor function here. */
  functionDestroy(db, p);

  if( pDestructor ){
    pDestructor->nRef++;
  }
  p->pDestructor = pDestructor;
  p->flags = 0;
  p->xFunc = xFunc;
  p->xStep = xStep;
  p->xFinalize = xFinal;
  p->pUserData = pUserData;
  p->nArg = (u16)nArg;
  return SQLITE4_OK;
}

/*
** This function is the same as sqlite4_create_function(), except that
** it does not grab the database handle mutex or call sqlite4ApiExit().
*/
static int createFunctionDestructor(
  sqlite4 *db,
  const char *zFunc,
  int nArg,
  void *p,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*),
  void (*xDestroy)(void *)
){
  int rc;
  FuncDestructor *pArg = 0;

  if( xDestroy ){
    pArg = (FuncDestructor *)sqlite4DbMallocZero(db, sizeof(FuncDestructor));
    if( !pArg ){
      xDestroy(p);
      return SQLITE4_NOMEM;
    }
    pArg->xDestroy = xDestroy;
    pArg->pUserData = p;
  }
  rc = sqlite4CreateFunc(db, zFunc, nArg, p, xFunc, xStep, xFinal, pArg);
  if( pArg && pArg->nRef==0 ){
    assert( rc!=SQLITE4_OK );
    xDestroy(p);
    sqlite4DbFree(db, pArg);
  }

  return rc;
}

/*
** Create new user functions.
*/
int sqlite4_create_function(
  sqlite4 *db,
  const char *zFunc,
  int nArg,
................................................................................
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*),
  void (*xDestroy)(void *)
){
  int rc;
  sqlite4_mutex_enter(db->mutex);
  rc = createFunctionDestructor(
      db, zFunc, nArg, p, xFunc, xStep, xFinal, xDestroy
  );
  rc = sqlite4ApiExit(db, rc);

  sqlite4_mutex_leave(db->mutex);
  return rc;
}

int sqlite4_create_mi_function(
  sqlite4 *db,
  const char *zFunc,







|
<
<


<
<
<
<
<
<
<
>
>







 







|







 







|
<
<
<









<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|



>







322
323
324
325
326
327
328
329


330
331







332
333
334
335
336
337
338
339
340
...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
...
577
578
579
580
581
582
583
584



585
586
587
588
589
590
591
592
593




































594
595
596
597
598
599
600
...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  }
  db->nSavepoint = 0;
  db->nStatement = 0;
}

/*
** Invoke the destructor function associated with FuncDef p, if any. Except,
** if this is not the last copy of the function, do not invoke it.


*/
static void functionDestroy(sqlite4 *db, FuncDef *p){







  if( p->xDestroy ){
    p->xDestroy(p->pUserData);
  }
}

/*
** Close an existing SQLite database
*/
int sqlite4_close(sqlite4 *db, unsigned int flags){
................................................................................
  sqlite4 *db,
  const char *zFunctionName,
  int nArg,
  void *pUserData,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*),
  void (*xDestroy)(void *)
){
  FuncDef *p;
  int nName;

  assert( sqlite4_mutex_held(db->mutex) );
  if( zFunctionName==0 ||
      (xFunc && (xFinal || xStep)) || 
................................................................................
    return SQLITE4_NOMEM;
  }

  /* If an older version of the function with a configured destructor is
  ** being replaced invoke the destructor function here. */
  functionDestroy(db, p);

  p->xDestroy = xDestroy;



  p->flags = 0;
  p->xFunc = xFunc;
  p->xStep = xStep;
  p->xFinalize = xFinal;
  p->pUserData = pUserData;
  p->nArg = (u16)nArg;
  return SQLITE4_OK;
}





































/*
** Create new user functions.
*/
int sqlite4_create_function(
  sqlite4 *db,
  const char *zFunc,
  int nArg,
................................................................................
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*),
  void (*xDestroy)(void *)
){
  int rc;
  sqlite4_mutex_enter(db->mutex);
  rc = sqlite4CreateFunc(
      db, zFunc, nArg, p, xFunc, xStep, xFinal, xDestroy
  );
  rc = sqlite4ApiExit(db, rc);
  if( rc!=SQLITE4_OK && xDestroy ) xDestroy(p);
  sqlite4_mutex_leave(db->mutex);
  return rc;
}

int sqlite4_create_mi_function(
  sqlite4 *db,
  const char *zFunc,

Changes to src/pragma.c.

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    void (*xFunc)(sqlite4_context *, int, sqlite4_value **);
    void (*xDestroy)(void *);
    void *pArg;

    rc = pKV->pStoreVfunc->xGetMethod(pKV, zPragma, &pArg, &xFunc, &xDestroy);
    if( rc==SQLITE4_OK ){
      FuncDef *pDef;
      int nByte;
      int r1 = 0;
      int regOut;               /* Result register */

      if( sqlite4AuthCheck(pParse, SQLITE4_PRAGMA, zPragma, 0, zDb) ){
        goto pragma_out;
      }

      nByte = sizeof(FuncDef) + sizeof(FuncDestructor);
      pDef = (FuncDef *)sqlite4DbMallocZero(db, nByte);
      if( !pDef ) goto pragma_out;
      pDef->flags = SQLITE4_FUNC_EPHEM;
      pDef->pUserData = pArg;
      pDef->xFunc = xFunc;
      pDef->pDestructor = (FuncDestructor *)&pDef[1];
      pDef->pDestructor->nRef = 1;
      pDef->pDestructor->xDestroy = xDestroy;
      pDef->pDestructor->pUserData = pArg;

      sqlite4VdbeSetNumCols(v, 1);
      sqlite4VdbeSetColName(v, 0, COLNAME_NAME, zPragma, SQLITE4_TRANSIENT);

      if( pList ){
        r1 = pParse->nMem+1;
        pParse->nMem += pList->nExpr;







<







<
|




<
<
|
<







197
198
199
200
201
202
203

204
205
206
207
208
209
210

211
212
213
214
215


216

217
218
219
220
221
222
223
    void (*xFunc)(sqlite4_context *, int, sqlite4_value **);
    void (*xDestroy)(void *);
    void *pArg;

    rc = pKV->pStoreVfunc->xGetMethod(pKV, zPragma, &pArg, &xFunc, &xDestroy);
    if( rc==SQLITE4_OK ){
      FuncDef *pDef;

      int r1 = 0;
      int regOut;               /* Result register */

      if( sqlite4AuthCheck(pParse, SQLITE4_PRAGMA, zPragma, 0, zDb) ){
        goto pragma_out;
      }


      pDef = (FuncDef *)sqlite4DbMallocZero(db, sizeof(FuncDef));
      if( !pDef ) goto pragma_out;
      pDef->flags = SQLITE4_FUNC_EPHEM;
      pDef->pUserData = pArg;
      pDef->xFunc = xFunc;


      pDef->xDestroy = xDestroy;


      sqlite4VdbeSetNumCols(v, 1);
      sqlite4VdbeSetColName(v, 0, COLNAME_NAME, zPragma, SQLITE4_TRANSIENT);

      if( pList ){
        r1 = pParse->nMem+1;
        pParse->nMem += pList->nExpr;

Changes to src/resolve.c.

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
      int no_such_func = 0;       /* True if no such function exists */
      int wrong_num_args = 0;     /* True if wrong number of arguments */
      int is_agg = 0;             /* True if is an aggregate function */
      int auth;                   /* Authorization to use the function */
      int nId;                    /* Number of characters in function name */
      const char *zId;            /* The function name. */
      FuncDef *pDef;              /* Information about the function */
      u8 enc = ENC(pParse->db);   /* The database encoding */

      testcase( pExpr->op==TK_CONST_FUNC );
      assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
      zId = pExpr->u.zToken;
      nId = sqlite4Strlen30(zId);
      pDef = sqlite4FindFunction(pParse->db, zId, nId, n, 0);
      if( pDef==0 ){







<







576
577
578
579
580
581
582

583
584
585
586
587
588
589
      int no_such_func = 0;       /* True if no such function exists */
      int wrong_num_args = 0;     /* True if wrong number of arguments */
      int is_agg = 0;             /* True if is an aggregate function */
      int auth;                   /* Authorization to use the function */
      int nId;                    /* Number of characters in function name */
      const char *zId;            /* The function name. */
      FuncDef *pDef;              /* Information about the function */


      testcase( pExpr->op==TK_CONST_FUNC );
      assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
      zId = pExpr->u.zToken;
      nId = sqlite4Strlen30(zId);
      pDef = sqlite4FindFunction(pParse->db, zId, nId, n, 0);
      if( pDef==0 ){

Changes to src/sqlite.h.in.

2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
#define SQLITE4_UTF8           1
#define SQLITE4_UTF16LE        2
#define SQLITE4_UTF16BE        3
#define SQLITE4_UTF16          4    /* Use native byte order */
#define SQLITE4_ANY            5    /* sqlite4_create_function only */
#define SQLITE4_UTF16_ALIGNED  8    /* sqlite4_create_collation only */

/*
** CAPIREF: Obtaining SQL Function Parameter Values
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on







<







2339
2340
2341
2342
2343
2344
2345

2346
2347
2348
2349
2350
2351
2352
** These constant define integer codes that represent the various
** text encodings supported by SQLite.
*/
#define SQLITE4_UTF8           1
#define SQLITE4_UTF16LE        2
#define SQLITE4_UTF16BE        3
#define SQLITE4_UTF16          4    /* Use native byte order */

#define SQLITE4_UTF16_ALIGNED  8    /* sqlite4_create_collation only */

/*
** CAPIREF: Obtaining SQL Function Parameter Values
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on

Changes to src/sqliteInt.h.

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
...
644
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
...
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
....
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct ExprListItem ExprListItem;
typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefTable FuncDefTable;
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct Fts5Index Fts5Index;
typedef struct Fts5Info Fts5Info;
typedef struct Fts5Cursor Fts5Cursor;
typedef struct IdList IdList;
................................................................................
  void *pUserData;     /* User data parameter */
  FuncDef *pSameName;  /* Next with a different name but the same hash */
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**); /* Regular function */
  void (*xStep)(sqlite4_context*,int,sqlite4_value**); /* Aggregate step */
  void (*xFinalize)(sqlite4_context*);                /* Aggregate finalizer */
  char *zName;         /* SQL name of the function. */
  FuncDef *pNextName;  /* Next function with a different name */
  FuncDestructor *pDestructor;   /* Reference counted destructor function */
  u8 bMatchinfo;       /* True for matchinfo function */

};

/*
** A table of SQL functions.  
**
** The content is a linked list of FuncDef structures with branches.  When
** there are two or more FuncDef objects with the same name, they are 
................................................................................
*/
#define SQLITE4_MAGIC_OPEN    0x4d06c919  /* Database is open */
#define SQLITE4_MAGIC_CLOSED  0x5f2246b4  /* Database is closed */
#define SQLITE4_MAGIC_SICK    0xcaad9e61  /* Error and awaiting close */
#define SQLITE4_MAGIC_BUSY    0xb07f8c8c  /* Database currently in use */
#define SQLITE4_MAGIC_ERROR   0x912e4c46  /* An SQLITE4_MISUSE error occurred */

/*
** This structure encapsulates a user-function destructor callback (as
** configured using create_function_v2()) and a reference counter. When
** create_function_v2() is called to create a function with a destructor,
** a single object of this type is allocated. FuncDestructor.nRef is set to 
** the number of FuncDef objects created (either 1 or 3, depending on whether
** or not the specified encoding is SQLITE4_ANY). The FuncDef.pDestructor
** member of each of the new FuncDef objects is set to point to the allocated
** FuncDestructor.
**
** Thereafter, when one of the FuncDef objects is deleted, the reference
** count on this object is decremented. When it reaches 0, the destructor
** is invoked and the FuncDestructor structure freed.
*/
struct FuncDestructor {
  int nRef;
  void (*xDestroy)(void *);
  void *pUserData;
};

/*
** Possible values for FuncDef.flags
*/
#define SQLITE4_FUNC_LIKE     0x01 /* Candidate for the LIKE optimization */
#define SQLITE4_FUNC_CASE     0x02 /* Case-sensitive LIKE-type function */
#define SQLITE4_FUNC_EPHEM    0x04 /* Ephemeral.  Delete with VDBE */
#define SQLITE4_FUNC_NEEDCOLL 0x08 /* sqlite4GetFuncCollSeq() might be called */
................................................................................
void sqlite4SchemaClear(sqlite4_env*,Schema*);
Schema *sqlite4SchemaGet(sqlite4*);
int sqlite4SchemaToIndex(sqlite4 *db, Schema *);
KeyInfo *sqlite4IndexKeyinfo(Parse *, Index *);
int sqlite4CreateFunc(sqlite4 *, const char *, int, void *, 
  void (*)(sqlite4_context*,int,sqlite4_value **),
  void (*)(sqlite4_context*,int,sqlite4_value **), void (*)(sqlite4_context*),
  FuncDestructor *pDestructor
);
int sqlite4ApiExit(sqlite4 *db, int);
int sqlite4OpenTempDatabase(Parse *);

void sqlite4StrAccumInit(StrAccum*, char*, int, int);
void sqlite4StrAccumAppend(StrAccum*,const char*,int);
void sqlite4AppendSpace(StrAccum*,int);







<







 







<

>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|







566
567
568
569
570
571
572

573
574
575
576
577
578
579
...
643
644
645
646
647
648
649

650
651
652
653
654
655
656
657
658
...
929
930
931
932
933
934
935




















936
937
938
939
940
941
942
....
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct ExprListItem ExprListItem;
typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;

typedef struct FuncDef FuncDef;
typedef struct FuncDefTable FuncDefTable;
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct Fts5Index Fts5Index;
typedef struct Fts5Info Fts5Info;
typedef struct Fts5Cursor Fts5Cursor;
typedef struct IdList IdList;
................................................................................
  void *pUserData;     /* User data parameter */
  FuncDef *pSameName;  /* Next with a different name but the same hash */
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**); /* Regular function */
  void (*xStep)(sqlite4_context*,int,sqlite4_value**); /* Aggregate step */
  void (*xFinalize)(sqlite4_context*);                 /* Aggregate finalizer */
  char *zName;         /* SQL name of the function. */
  FuncDef *pNextName;  /* Next function with a different name */

  u8 bMatchinfo;       /* True for matchinfo function */
  void (*xDestroy)(void *);       /* Users destructor function */
};

/*
** A table of SQL functions.  
**
** The content is a linked list of FuncDef structures with branches.  When
** there are two or more FuncDef objects with the same name, they are 
................................................................................
*/
#define SQLITE4_MAGIC_OPEN    0x4d06c919  /* Database is open */
#define SQLITE4_MAGIC_CLOSED  0x5f2246b4  /* Database is closed */
#define SQLITE4_MAGIC_SICK    0xcaad9e61  /* Error and awaiting close */
#define SQLITE4_MAGIC_BUSY    0xb07f8c8c  /* Database currently in use */
#define SQLITE4_MAGIC_ERROR   0x912e4c46  /* An SQLITE4_MISUSE error occurred */





















/*
** Possible values for FuncDef.flags
*/
#define SQLITE4_FUNC_LIKE     0x01 /* Candidate for the LIKE optimization */
#define SQLITE4_FUNC_CASE     0x02 /* Case-sensitive LIKE-type function */
#define SQLITE4_FUNC_EPHEM    0x04 /* Ephemeral.  Delete with VDBE */
#define SQLITE4_FUNC_NEEDCOLL 0x08 /* sqlite4GetFuncCollSeq() might be called */
................................................................................
void sqlite4SchemaClear(sqlite4_env*,Schema*);
Schema *sqlite4SchemaGet(sqlite4*);
int sqlite4SchemaToIndex(sqlite4 *db, Schema *);
KeyInfo *sqlite4IndexKeyinfo(Parse *, Index *);
int sqlite4CreateFunc(sqlite4 *, const char *, int, void *, 
  void (*)(sqlite4_context*,int,sqlite4_value **),
  void (*)(sqlite4_context*,int,sqlite4_value **), void (*)(sqlite4_context*),
  void (*)(void *)
);
int sqlite4ApiExit(sqlite4 *db, int);
int sqlite4OpenTempDatabase(Parse *);

void sqlite4StrAccumInit(StrAccum*, char*, int, int);
void sqlite4StrAccumAppend(StrAccum*,const char*,int);
void sqlite4AppendSpace(StrAccum*,int);

Changes to src/vdbeaux.c.

564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579

/*
** If the input FuncDef structure is ephemeral, then free it.  If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite4 *db, FuncDef *pDef){
  if( ALWAYS(pDef) && (pDef->flags & SQLITE4_FUNC_EPHEM)!=0 ){
    if( pDef->pDestructor->xDestroy ){
      pDef->pDestructor->xDestroy(pDef->pDestructor->pUserData);
    }
    sqlite4DbFree(db, pDef);
  }
}

static void vdbeFreeOpArray(sqlite4 *, Op *, int);








|
|







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579

/*
** If the input FuncDef structure is ephemeral, then free it.  If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite4 *db, FuncDef *pDef){
  if( ALWAYS(pDef) && (pDef->flags & SQLITE4_FUNC_EPHEM)!=0 ){
    if( pDef->xDestroy ){
      pDef->xDestroy(pDef->pUserData);
    }
    sqlite4DbFree(db, pDef);
  }
}

static void vdbeFreeOpArray(sqlite4 *, Op *, int);

Changes to test/func3.test.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
set testdir [file dirname $argv0]
source $testdir/tester.tcl


do_test func3-2.1 {
  set destroyed 0
  proc destroy {} { set ::destroyed 1 }
  sqlite4_create_function_v2 db f3 -1 utf8 -func f3 -destroy destroy
  set destroyed
} 0
do_test func3-2.2 {
  sqlite4_create_function_v2 db f3 -1 utf8 -func f3
  set destroyed
} 1

do_test func3-3.1 {
  set destroyed 0
  proc destroy {} { set ::destroyed 1 }
  sqlite4_create_function_v2 db f3 -1 any -func f3 -destroy destroy
  set destroyed
} 0
do_test func3-3.2 {
  db close
  set destroyed
} 1

sqlite4 db test.db
do_test func3-4.1 {
  set destroyed 0
  set rc [catch { 
    sqlite4_create_function_v2 db f3 -1 any -func f3 -step f3 -destroy destroy
  } msg]
  list $rc $msg
} {1 SQLITE4_MISUSE}
do_test func3-4.2 { set destroyed } 1

finish_test







|



|






|











|






16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
set testdir [file dirname $argv0]
source $testdir/tester.tcl


do_test func3-2.1 {
  set destroyed 0
  proc destroy {} { set ::destroyed 1 }
  sqlite4_create_function_v2 db f3 -1 -func f3 -destroy destroy
  set destroyed
} 0
do_test func3-2.2 {
  sqlite4_create_function_v2 db f3 -1 -func f3
  set destroyed
} 1

do_test func3-3.1 {
  set destroyed 0
  proc destroy {} { set ::destroyed 1 }
  sqlite4_create_function_v2 db f3 -1 -func f3 -destroy destroy
  set destroyed
} 0
do_test func3-3.2 {
  db close
  set destroyed
} 1

sqlite4 db test.db
do_test func3-4.1 {
  set destroyed 0
  set rc [catch { 
    sqlite4_create_function_v2 db f3 -1 -func f3 -step f3 -destroy destroy
  } msg]
  list $rc $msg
} {1 SQLITE4_MISUSE}
do_test func3-4.2 { set destroyed } 1

finish_test

Changes to test/test_main.c.

1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
  Tcl_Interp *interp,             /* The invoking TCL interpreter */
  int objc,                       /* Number of arguments */
  Tcl_Obj *CONST objv[]           /* Command arguments */
){
  sqlite4 *db;
  const char *zFunc;
  int nArg;
  int enc;
  CreateFunctionV2 *p;
  int i;
  int rc;

  struct EncTable {
    const char *zEnc;
    int enc;
  } aEnc[] = {
    {"utf8",    SQLITE4_UTF8 },
    {"utf16",   SQLITE4_UTF16 },
    {"utf16le", SQLITE4_UTF16LE },
    {"utf16be", SQLITE4_UTF16BE },
    {"any",     SQLITE4_ANY },
    {"0", 0 }
  };

  if( objc<5 || (objc%2)==0 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES...");
    return TCL_ERROR;
  }

  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zFunc = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR;
  if( Tcl_GetIndexFromObjStruct(interp, objv[4], aEnc, sizeof(aEnc[0]), 
          "encoding", 0, &enc)
  ){
    return TCL_ERROR;
  }
  enc = aEnc[enc].enc;

  p = sqlite4_malloc(0, sizeof(CreateFunctionV2));
  assert( p );
  memset(p, 0, sizeof(CreateFunctionV2));
  p->interp = interp;

  for(i=5; i<objc; i+=2){
    int iSwitch;
    const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0};
    if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){
      sqlite4_free(0, p);
      return TCL_ERROR;
    }








<




<
<
<
<
<
<
<
<
<
<
<
<
|
|






<
<
<
<
<
<






|







1470
1471
1472
1473
1474
1475
1476

1477
1478
1479
1480












1481
1482
1483
1484
1485
1486
1487
1488






1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  Tcl_Interp *interp,             /* The invoking TCL interpreter */
  int objc,                       /* Number of arguments */
  Tcl_Obj *CONST objv[]           /* Command arguments */
){
  sqlite4 *db;
  const char *zFunc;
  int nArg;

  CreateFunctionV2 *p;
  int i;
  int rc;













  if( objc<4 || (objc%2) ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG SWITCHES...");
    return TCL_ERROR;
  }

  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zFunc = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR;







  p = sqlite4_malloc(0, sizeof(CreateFunctionV2));
  assert( p );
  memset(p, 0, sizeof(CreateFunctionV2));
  p->interp = interp;

  for(i=4; i<objc; i+=2){
    int iSwitch;
    const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0};
    if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){
      sqlite4_free(0, p);
      return TCL_ERROR;
    }