SQLite4
Check-in [b7612a4adb]
Not logged in

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

Overview
Comment:Add a destructor parameter to sqlite4_create_function() and create_function16(). Remove create_function_v2().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b7612a4adb70a6ddf83493c51b63ca6bb497fdfb
User & Date: dan 2013-05-09 19:12:16
Context
2013-05-09
19:47
Add an "unsigned int flags" parameter to sqlite4_close(). Currently unused. check-in: 95275bb370 user: dan tags: trunk
19:12
Add a destructor parameter to sqlite4_create_function() and create_function16(). Remove create_function_v2(). check-in: b7612a4adb user: dan tags: trunk
18:11
Have sqlite4_column_text() and other functions return the size of the returned buffer in bytes via an optional output parameter. Remove sqlite4_column_bytes() and similar. check-in: 51c6f56d73 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/fts5.c.

3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419

/*
** Register the default FTS5 tokenizer and functions with handle db.
*/
int sqlite4InitFts5(sqlite4 *db){
#ifdef SQLITE4_TEST
  int rc = sqlite4_create_function(
      db, "fts5_parse_expr", 3, SQLITE4_UTF8, 0, fts5_parse_expr, 0, 0
  );
  if( rc!=SQLITE4_OK ) return rc;
#endif
  return sqlite4InitFts5Func(db);
}







|





3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419

/*
** Register the default FTS5 tokenizer and functions with handle db.
*/
int sqlite4InitFts5(sqlite4 *db){
#ifdef SQLITE4_TEST
  int rc = sqlite4_create_function(
      db, "fts5_parse_expr", 3, SQLITE4_UTF8, 0, fts5_parse_expr, 0, 0, 0
  );
  if( rc!=SQLITE4_OK ) return rc;
#endif
  return sqlite4InitFts5Func(db);
}

Changes to src/main.c.

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
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674





















675
676
677
678
679
680
681
...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
...
702
703
704
705
706
707
708
709
710
711
712
713

714
715
716
717
718
719
720


721
722
723
724
725
726
727
  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,
  int enc,
  void *p,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value **),
  void (*xStep)(sqlite4_context*,int,sqlite4_value **),
  void (*xFinal)(sqlite4_context*)
){
  return sqlite4_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
                                    xFinal, 0);
}

int sqlite4_create_function_v2(
  sqlite4 *db,
  const char *zFunc,
  int nArg,
  int enc,
  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 = SQLITE4_ERROR;
  FuncDestructor *pArg = 0;
  sqlite4_mutex_enter(db->mutex);
  if( xDestroy ){
    pArg = (FuncDestructor *)sqlite4DbMallocZero(db, sizeof(FuncDestructor));
    if( !pArg ){
      xDestroy(p);
      goto out;
    }
    pArg->xDestroy = xDestroy;
    pArg->pUserData = p;
  }
  rc = sqlite4CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
  if( pArg && pArg->nRef==0 ){
    assert( rc!=SQLITE4_OK );
    xDestroy(p);
    sqlite4DbFree(db, pArg);
  }

 out:





















  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
}

int sqlite4_create_mi_function(
  sqlite4 *db,
................................................................................
  void (*xDestroy)(void *)
){
  int rc;
  int n;

  n = nArg + (nArg>=0);
  sqlite4_mutex_enter(db->mutex);
  rc = sqlite4_create_function_v2(db, zFunc, n, enc, p, xFunc, 0,0,xDestroy);
  if( rc==SQLITE4_OK ){
    FuncDef *p = sqlite4FindFunction(db, zFunc, -1, n, enc, 0);
    p->bMatchinfo = 1;
  }
  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
................................................................................
}

#ifndef SQLITE4_OMIT_UTF16
int sqlite4_create_function16(
  sqlite4 *db,
  const void *zFunctionName,
  int nArg,
  int eTextRep,
  void *p,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*)

){
  int rc;
  char *zFunc8;
  sqlite4_mutex_enter(db->mutex);
  assert( !db->mallocFailed );
  zFunc8 = sqlite4Utf16to8(db, zFunctionName, -1, SQLITE4_UTF16NATIVE);
  rc = sqlite4CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);


  sqlite4DbFree(db, zFunc8);
  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
}
#endif








|
>

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










|
|
|




|











|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|



|
>






|
>
>







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
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
...
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
  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,
  int enc,
  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, enc, 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,
  int enc,
  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;
  sqlite4_mutex_enter(db->mutex);
  rc = createFunctionDestructor(
      db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, xDestroy
  );
  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
}

int sqlite4_create_mi_function(
  sqlite4 *db,
................................................................................
  void (*xDestroy)(void *)
){
  int rc;
  int n;

  n = nArg + (nArg>=0);
  sqlite4_mutex_enter(db->mutex);
  rc = sqlite4_create_function(db, zFunc, n, enc, p, xFunc, 0,0, xDestroy);
  if( rc==SQLITE4_OK ){
    FuncDef *p = sqlite4FindFunction(db, zFunc, -1, n, enc, 0);
    p->bMatchinfo = 1;
  }
  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
................................................................................
}

#ifndef SQLITE4_OMIT_UTF16
int sqlite4_create_function16(
  sqlite4 *db,
  const void *zFunctionName,
  int nArg,
  int enc,
  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;
  char *zFunc8;
  sqlite4_mutex_enter(db->mutex);
  assert( !db->mallocFailed );
  zFunc8 = sqlite4Utf16to8(db, zFunctionName, -1, SQLITE4_UTF16NATIVE);
  rc = createFunctionDestructor(
      db, zFunc8, nArg, enc, p, xFunc, xStep, xFinal, xDestroy
  );
  sqlite4DbFree(db, zFunc8);
  rc = sqlite4ApiExit(db, rc);
  sqlite4_mutex_leave(db->mutex);
  return rc;
}
#endif

Changes to src/shell.c.

1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
*/
static void open_db(struct callback_data *p){
  if( p->db==0 ){
    sqlite4_open(0, p->zDbFilename, &p->db, 0);
    db = p->db;
    if( db && sqlite4_errcode(db)==SQLITE4_OK ){
      sqlite4_create_function(db, "shellstatic", 0, SQLITE4_UTF8, 0,
          shellstaticFunc, 0, 0);
    }
    if( db==0 || SQLITE4_OK!=sqlite4_errcode(db) ){
      fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 
          p->zDbFilename, sqlite4_errmsg(db));
      exit(1);
    }
#if 0 /*ndef SQLITE4_OMIT_LOAD_EXTENSION*/







|







1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
*/
static void open_db(struct callback_data *p){
  if( p->db==0 ){
    sqlite4_open(0, p->zDbFilename, &p->db, 0);
    db = p->db;
    if( db && sqlite4_errcode(db)==SQLITE4_OK ){
      sqlite4_create_function(db, "shellstatic", 0, SQLITE4_UTF8, 0,
          shellstaticFunc, 0, 0, 0);
    }
    if( db==0 || SQLITE4_OK!=sqlite4_errcode(db) ){
      fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 
          p->zDbFilename, sqlite4_errmsg(db));
      exit(1);
    }
#if 0 /*ndef SQLITE4_OMIT_LOAD_EXTENSION*/

Changes to src/sqlite.h.in.

2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
....
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431

2432
2433
2434
2435
2436
2437
2438
....
2454
2455
2456
2457
2458
2459
2460
2461

2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
/*
** CAPIREF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
** of existing SQL functions or aggregates.  The only differences between
** these routines are the text encoding expected for
** the second parameter (the name of the function being created)
** and the presence or absence of a destructor callback for
** the application data pointer.
**
** ^The first parameter is the [database connection] to which the SQL
** function is to be added.  ^If an application uses more than one database
** connection then application-defined SQL functions must be added
** to each database connection separately.
**
** ^The second parameter is the name of the SQL function to be created or
** redefined.  ^The length of the name is limited to 255 bytes in a UTF-8
** representation, exclusive of the zero-terminator.  ^Note that the name
** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.  
** ^Any attempt to create a function with a longer name
** will result in [SQLITE4_MISUSE] being returned.
**
** ^The third parameter (nArg)
** is the number of arguments that the SQL function or
** aggregate takes. ^If this parameter is -1, then the SQL function or
** aggregate may take any number of arguments between 0 and the limit
** set by [sqlite4_limit]([SQLITE4_LIMIT_FUNCTION_ARG]).  If the third
** parameter is less than -1 or greater than 127 then the behavior is
** undefined.
**
** ^The fourth parameter, eTextRep, specifies what
** [SQLITE4_UTF8 | text encoding] this SQL function prefers for
** its parameters.  Every SQL function implementation must be able to work
** with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
** more efficient with one encoding than another.  ^An application may
** invoke sqlite4_create_function() or sqlite4_create_function16() multiple
** times with the same function but with different values of eTextRep.
** ^When multiple implementations of the same function are available, SQLite
................................................................................
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
** callback only; NULL pointers must be passed as the xStep and xFinal
** parameters. ^An aggregate SQL function requires an implementation of xStep
** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
** SQL function or aggregate, pass NULL pointers for all three function
** callbacks.
**
** ^(If the ninth parameter to sqlite4_create_function_v2() is not NULL,
** then it is destructor for the application data pointer. 
** The destructor is invoked when the function is deleted, either by being
** overloaded or when the database connection closes.)^
** ^The destructor is also invoked if the call to
** sqlite4_create_function_v2() fails.
** ^When the destructor callback of the tenth parameter is invoked, it
** is passed a single argument which is a copy of the application data 
** pointer which was the fifth parameter to sqlite4_create_function_v2().

**
** ^It is permitted to register multiple implementations of the same
** functions with the same name but with either differing numbers of
** arguments or differing preferred text encodings.  ^SQLite will use
** the implementation that most closely matches the way in which the
** SQL function is used.  ^A function implementation with a non-negative
** nArg parameter is a better match than a function implementation with
................................................................................
  sqlite4 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*)

);
int sqlite4_create_function16(
  sqlite4 *db,
  const void *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*)
);
int sqlite4_create_function_v2(
  sqlite4 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*),
  void(*xDestroy)(void*)
);







|
<
|
|
<
<













<
|
|
|
|
|
|

|







 







|
<
|
|
|
|
<
|
|
>







 







|
>





<
<
<
<
<
<
<
<
<
<







2365
2366
2367
2368
2369
2370
2371
2372

2373
2374


2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387

2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
....
2412
2413
2414
2415
2416
2417
2418
2419

2420
2421
2422
2423

2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
....
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462










2463
2464
2465
2466
2467
2468
2469
/*
** CAPIREF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
**
** ^These functions (collectively known as "function creation routines")
** are used to add new SQL scalar or aggregate functions. The only 

** difference between the two routines is the text encoding expected for 
** the second parameter (the name of the function being created).


**
** ^The first parameter is the [database connection] to which the SQL
** function is to be added.  ^If an application uses more than one database
** connection then application-defined SQL functions must be added
** to each database connection separately.
**
** ^The second parameter is the name of the SQL function to be created or
** redefined.  ^The length of the name is limited to 255 bytes in a UTF-8
** representation, exclusive of the zero-terminator.  ^Note that the name
** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.  
** ^Any attempt to create a function with a longer name
** will result in [SQLITE4_MISUSE] being returned.
**

** ^The third parameter (nArg) is the number of arguments that the SQL 
** function or aggregate takes. ^If this parameter is -1, then the SQL 
** function or aggregate may take any number of arguments between 0 and 
** the limit set by [sqlite4_limit]([SQLITE4_LIMIT_FUNCTION_ARG]).  If 
** the third parameter is less than -1 or greater than 127 then the 
** behavior is undefined.
**
** ^The fourth parameter, eTextRep, specifies the
** [SQLITE4_UTF8 | text encoding] this SQL function prefers for
** its parameters.  Every SQL function implementation must be able to work
** with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
** more efficient with one encoding than another.  ^An application may
** invoke sqlite4_create_function() or sqlite4_create_function16() multiple
** times with the same function but with different values of eTextRep.
** ^When multiple implementations of the same function are available, SQLite
................................................................................
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
** callback only; NULL pointers must be passed as the xStep and xFinal
** parameters. ^An aggregate SQL function requires an implementation of xStep
** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
** SQL function or aggregate, pass NULL pointers for all three function
** callbacks.
**
** ^(If the ninth parameter is not NULL, then it is destructor for the 

** application data pointer. The destructor is invoked when the function 
** is deleted, either by being overloaded or when the database connection 
** closes.)^ ^The destructor is also invoked if the call to
** sqlite4_create_function() fails. ^When the destructor callback 

** is invoked, it is passed a single argument which is a copy of the 
** application data pointer which was the fifth parameter to 
** sqlite4_create_function().
**
** ^It is permitted to register multiple implementations of the same
** functions with the same name but with either differing numbers of
** arguments or differing preferred text encodings.  ^SQLite will use
** the implementation that most closely matches the way in which the
** SQL function is used.  ^A function implementation with a non-negative
** nArg parameter is a better match than a function implementation with
................................................................................
  sqlite4 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*),
  void(*xDestroy)(void*)
);
int sqlite4_create_function16(
  sqlite4 *db,
  const void *zFunctionName,
  int nArg,










  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite4_context*,int,sqlite4_value**),
  void (*xStep)(sqlite4_context*,int,sqlite4_value**),
  void (*xFinal)(sqlite4_context*),
  void(*xDestroy)(void*)
);

Changes to src/tclsqlite.c.

1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
....
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
    if( pFunc->pScript ){
      Tcl_DecrRefCount(pFunc->pScript);
    }
    pFunc->pScript = pScript;
    Tcl_IncrRefCount(pScript);
    pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
    rc = sqlite4_create_function(pDb->db, zName, nArg, SQLITE4_UTF8,
        pFunc, tclSqlFunc, 0, 0);
    if( rc!=SQLITE4_OK ){
      rc = TCL_ERROR;
      Tcl_SetResult(interp, (char *)sqlite4_errmsg(pDb->db), TCL_VOLATILE);
    }
    break;
  }

................................................................................
  p = sqlite4_aggregate_context(context, sizeof(*p));
  MD5Final(digest,p);
  MD5DigestToBase16(digest, zBuf);
  sqlite4_result_text(context, zBuf, -1, SQLITE4_TRANSIENT, 0);
}
int Md5_Register(sqlite4 *db){
  int rc = sqlite4_create_function(db, "md5sum", -1, SQLITE4_UTF8, 0, 0, 
                                 md5step, md5finalize);
  sqlite4_overload_function(db, "md5sum", -1);  /* To exercise this API */
  return rc;
}
#endif /* defined(SQLITE4_TEST) */


/*







|







 







|







1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
....
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
    if( pFunc->pScript ){
      Tcl_DecrRefCount(pFunc->pScript);
    }
    pFunc->pScript = pScript;
    Tcl_IncrRefCount(pScript);
    pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
    rc = sqlite4_create_function(pDb->db, zName, nArg, SQLITE4_UTF8,
        pFunc, tclSqlFunc, 0, 0, 0);
    if( rc!=SQLITE4_OK ){
      rc = TCL_ERROR;
      Tcl_SetResult(interp, (char *)sqlite4_errmsg(pDb->db), TCL_VOLATILE);
    }
    break;
  }

................................................................................
  p = sqlite4_aggregate_context(context, sizeof(*p));
  MD5Final(digest,p);
  MD5DigestToBase16(digest, zBuf);
  sqlite4_result_text(context, zBuf, -1, SQLITE4_TRANSIENT, 0);
}
int Md5_Register(sqlite4 *db){
  int rc = sqlite4_create_function(db, "md5sum", -1, SQLITE4_UTF8, 0, 0, 
                                 md5step, md5finalize, 0);
  sqlite4_overload_function(db, "md5sum", -1);  /* To exercise this API */
  return rc;
}
#endif /* defined(SQLITE4_TEST) */


/*

Changes to test/test_func.c.

461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
...
496
497
498
499
500
501
502
503

504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
    { "test_isolation",        2, SQLITE4_UTF8, test_isolation},
    { "test_counter",          1, SQLITE4_UTF8, counterFunc},
  };
  int i;

  for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
    sqlite4_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
        aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0);
  }

  sqlite4_create_function(db, "test_agg_errmsg16", 0, SQLITE4_ANY, 0, 0, 
      test_agg_errmsg16_step, test_agg_errmsg16_final);
      
  return SQLITE4_OK;
}

/*
** A bogus step function and finalizer function.
*/
................................................................................
  extern int getDbPointer(Tcl_Interp*, const char*, sqlite4**);
  sqlite4 *db;
  int rc;
  int mxArg;

  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, tStep,tStep,tFinal);

  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, tStep, tStep, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, tStep, 0, tFinal);
  if( rc!=SQLITE4_MISUSE) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, 0, 0, tFinal);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, 0, tStep, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", -2, SQLITE4_UTF8, 0, tStep, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 128, SQLITE4_UTF8, 0, tStep, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "funcxx"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789",
       1, SQLITE4_UTF8, 0, tStep, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  /* This last function registration should actually work.  Generate
  ** a no-op function (that always returns NULL) and which has the
  ** maximum-length function name and the maximum number of parameters.
  */
  sqlite4_limit(db, SQLITE4_LIMIT_FUNCTION_ARG, 10000);
................................................................................
  mxArg = sqlite4_limit(db, SQLITE4_LIMIT_FUNCTION_ARG, -1);
  rc = sqlite4_create_function(db, "nullx"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789",
       mxArg, SQLITE4_UTF8, 0, tStep, 0, 0);
  if( rc!=SQLITE4_OK ) goto abuse_err;
                                
  return TCL_OK;

abuse_err:
  Tcl_AppendResult(interp, "sqlite4_create_function abused test failed", 
                   (char*)0);







|



|







 







|
>


|


|


|


|


|


|








|







 







|







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
    { "test_isolation",        2, SQLITE4_UTF8, test_isolation},
    { "test_counter",          1, SQLITE4_UTF8, counterFunc},
  };
  int i;

  for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
    sqlite4_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
        aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0, 0);
  }

  sqlite4_create_function(db, "test_agg_errmsg16", 0, SQLITE4_ANY, 0, 0, 
      test_agg_errmsg16_step, test_agg_errmsg16_final, 0);
      
  return SQLITE4_OK;
}

/*
** A bogus step function and finalizer function.
*/
................................................................................
  extern int getDbPointer(Tcl_Interp*, const char*, sqlite4**);
  sqlite4 *db;
  int rc;
  int mxArg;

  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  rc = sqlite4_create_function(
      db, "tx", 1, SQLITE4_UTF8, 0, tStep, tStep, tFinal, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, tStep, tStep, 0,0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, tStep, 0,tFinal,0);
  if( rc!=SQLITE4_MISUSE) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, 0, 0, tFinal, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 1, SQLITE4_UTF8, 0, 0, tStep, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", -2, SQLITE4_UTF8, 0, tStep, 0, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "tx", 128, SQLITE4_UTF8, 0, tStep, 0, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  rc = sqlite4_create_function(db, "funcxx"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789",
       1, SQLITE4_UTF8, 0, tStep, 0, 0, 0);
  if( rc!=SQLITE4_MISUSE ) goto abuse_err;

  /* This last function registration should actually work.  Generate
  ** a no-op function (that always returns NULL) and which has the
  ** maximum-length function name and the maximum number of parameters.
  */
  sqlite4_limit(db, SQLITE4_LIMIT_FUNCTION_ARG, 10000);
................................................................................
  mxArg = sqlite4_limit(db, SQLITE4_LIMIT_FUNCTION_ARG, -1);
  rc = sqlite4_create_function(db, "nullx"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789"
       "_123456789_123456789_123456789_123456789_123456789",
       mxArg, SQLITE4_UTF8, 0, tStep, 0, 0, 0);
  if( rc!=SQLITE4_OK ) goto abuse_err;
                                
  return TCL_OK;

abuse_err:
  Tcl_AppendResult(interp, "sqlite4_create_function abused test failed", 
                   (char*)0);

Changes to test/test_main.c.

846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
...
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
...
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
....
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
....
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
....
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
....
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " DB\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, "x_coalesce", -1, SQLITE4_ANY, 0, 
        t1_ifnullFunc, 0, 0);
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "hex8", 1, SQLITE4_ANY, 0, 
          hex8Func, 0, 0);
  }
#ifndef SQLITE4_OMIT_UTF16
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "hex16", 1, SQLITE4_ANY, 0, 
          hex16Func, 0, 0);
  }
#endif
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "tkt2213func", 1, SQLITE4_ANY, 0, 
          tkt2213Function, 0, 0);
  }

#ifndef SQLITE4_OMIT_UTF16
  /* Use the sqlite4_create_function16() API here. Mainly for fun, but also 
  ** because it is not tested anywhere else. */
  if( rc==SQLITE4_OK ){
    const void *zUtf16;
................................................................................
    sqlite4ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE4_UTF8,
                       SQLITE4_STATIC, 0);
    zUtf16 = sqlite4ValueText(pVal, SQLITE4_UTF16NATIVE);
    if( db->mallocFailed ){
      rc = SQLITE4_NOMEM;
    }else{
      rc = sqlite4_create_function16(db, zUtf16, 
                1, SQLITE4_UTF16, db, sqlite4ExecFunc, 0, 0);
    }
    sqlite4ValueFree(pVal);
    sqlite4_mutex_leave(db->mutex);
  }
#endif

  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, "x_count", 0, SQLITE4_UTF8, 0, 0,
      t1CountStep,t1CountFinalize);
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "x_count", 1, SQLITE4_UTF8, 0, 0,
        t1CountStep,t1CountFinalize);
  }
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  return TCL_OK;
}


................................................................................
  if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy); 

  if( p->pFunc ) Tcl_IncrRefCount(p->pFunc); 
  if( p->pStep ) Tcl_IncrRefCount(p->pStep); 
  if( p->pFinal ) Tcl_IncrRefCount(p->pFinal); 
  if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy); 

  rc = sqlite4_create_function_v2(db, zFunc, nArg, enc, (void *)p, 
      (p->pFunc ? cf2Func : 0),
      (p->pStep ? cf2Step : 0),
      (p->pFinal ? cf2Final : 0),
      cf2Destroy
  );
  if( rc!=SQLITE4_OK ){
    Tcl_ResetResult(interp);
................................................................................
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
       " DB FUNCTION-NAME", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, argv[2], -1, SQLITE4_UTF8, 0, 
      testFunc, 0, 0);
  if( rc!=0 ){
    Tcl_AppendResult(interp, sqlite4ErrStr(rc), 0);
    return TCL_ERROR;
  }
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  return TCL_OK;
}
................................................................................

  if( objc!=5 ) goto bad_args;
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF8, 
        interp, test_function_utf8, 0, 0);
  }
  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF16LE, 
        interp, test_function_utf16le, 0, 0);
  }
  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF16BE, 
        interp, test_function_utf16be, 0, 0);
  }

  return TCL_OK;
bad_args:
  Tcl_AppendResult(interp, "wrong # args: should be \"",
      Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
#endif /* SQLITE4_OMIT_UTF16 */
................................................................................
  sqlite4 *db;
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
        " DB function-name", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, argv[2], -1, SQLITE4_UTF8, 0, 0, 0, 0);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}

/*
** Usage: sqlite_delete_collation DB collation-name
**







|


|




|




|







 







|







 







|


|







 







|







 







|







 







|




|




|







 







|







846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
...
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
...
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
....
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
....
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
....
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
....
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " DB\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, "x_coalesce", -1, SQLITE4_ANY, 0, 
        t1_ifnullFunc, 0, 0, 0);
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "hex8", 1, SQLITE4_ANY, 0, 
          hex8Func, 0, 0, 0);
  }
#ifndef SQLITE4_OMIT_UTF16
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "hex16", 1, SQLITE4_ANY, 0, 
          hex16Func, 0, 0, 0);
  }
#endif
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "tkt2213func", 1, SQLITE4_ANY, 0, 
          tkt2213Function, 0, 0, 0);
  }

#ifndef SQLITE4_OMIT_UTF16
  /* Use the sqlite4_create_function16() API here. Mainly for fun, but also 
  ** because it is not tested anywhere else. */
  if( rc==SQLITE4_OK ){
    const void *zUtf16;
................................................................................
    sqlite4ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE4_UTF8,
                       SQLITE4_STATIC, 0);
    zUtf16 = sqlite4ValueText(pVal, SQLITE4_UTF16NATIVE);
    if( db->mallocFailed ){
      rc = SQLITE4_NOMEM;
    }else{
      rc = sqlite4_create_function16(db, zUtf16, 
                1, SQLITE4_UTF16, db, sqlite4ExecFunc, 0, 0, 0);
    }
    sqlite4ValueFree(pVal);
    sqlite4_mutex_leave(db->mutex);
  }
#endif

  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
................................................................................
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, "x_count", 0, SQLITE4_UTF8, 0, 0,
      t1CountStep, t1CountFinalize, 0);
  if( rc==SQLITE4_OK ){
    rc = sqlite4_create_function(db, "x_count", 1, SQLITE4_UTF8, 0, 0,
        t1CountStep, t1CountFinalize, 0);
  }
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  return TCL_OK;
}


................................................................................
  if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy); 

  if( p->pFunc ) Tcl_IncrRefCount(p->pFunc); 
  if( p->pStep ) Tcl_IncrRefCount(p->pStep); 
  if( p->pFinal ) Tcl_IncrRefCount(p->pFinal); 
  if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy); 

  rc = sqlite4_create_function(db, zFunc, nArg, enc, (void *)p, 
      (p->pFunc ? cf2Func : 0),
      (p->pStep ? cf2Step : 0),
      (p->pFinal ? cf2Final : 0),
      cf2Destroy
  );
  if( rc!=SQLITE4_OK ){
    Tcl_ResetResult(interp);
................................................................................
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
       " DB FUNCTION-NAME", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, argv[2], -1, SQLITE4_UTF8, 0, 
      testFunc, 0, 0, 0);
  if( rc!=0 ){
    Tcl_AppendResult(interp, sqlite4ErrStr(rc), 0);
    return TCL_ERROR;
  }
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  return TCL_OK;
}
................................................................................

  if( objc!=5 ) goto bad_args;
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;

  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF8, 
        interp, test_function_utf8, 0, 0, 0);
  }
  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF16LE, 
        interp, test_function_utf16le, 0, 0, 0);
  }
  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
  if( val ){
    sqlite4_create_function(db, "test_function", 1, SQLITE4_UTF16BE, 
        interp, test_function_utf16be, 0, 0, 0);
  }

  return TCL_OK;
bad_args:
  Tcl_AppendResult(interp, "wrong # args: should be \"",
      Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
#endif /* SQLITE4_OMIT_UTF16 */
................................................................................
  sqlite4 *db;
  if( argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
        " DB function-name", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite4_create_function(db, argv[2], -1, SQLITE4_UTF8, 0, 0, 0, 0, 0);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
  return TCL_OK;
}

/*
** Usage: sqlite_delete_collation DB collation-name
**