Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add destructors to the sqlite4_trace and sqlite4_profile routines. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
fd63f9cb75174abb04984f13de503f71 |
User & Date: | dan 2013-06-15 19:47:11.935 |
Context
2013-06-17
| ||
05:35 | Remove the sqlite4_progress_handler interface. Change the documentation of load_extension() to say that it sets the db handle error message and code. check-in: 02ec769ae0 user: dan tags: trunk | |
2013-06-15
| ||
19:47 | Add destructors to the sqlite4_trace and sqlite4_profile routines. check-in: fd63f9cb75 user: dan tags: trunk | |
17:45 | Add tests to ensure that the collation_needed destructor is invoked as required. check-in: 6e0b04adb9 user: dan tags: trunk | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
406 407 408 409 410 411 412 | sqlite4AuthFreeAll(db); /* Tell the code in notify.c that the connection no longer holds any ** locks and does not require any further unlock-notify callbacks. */ sqlite4ConnectionClosed(db); | | > > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | sqlite4AuthFreeAll(db); /* Tell the code in notify.c that the connection no longer holds any ** locks and does not require any further unlock-notify callbacks. */ sqlite4ConnectionClosed(db); /* Delete any collation needed, profile and trace callbacks */ sqlite4_collation_needed(db, 0, 0, 0); sqlite4_profile(db, 0, 0, 0); sqlite4_trace(db, 0, 0, 0); /* Delete tokenizers */ sqlite4ShutdownFts5(db); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); { |
︙ | ︙ | |||
688 689 690 691 692 693 694 | ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ | | > | > > > > | > > < | > | > | > > < | 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 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ void sqlite4_trace( sqlite4 *db, void *pArg, void (*xTrace)(void*,const char*), void (*xDestroy)(void*) ){ sqlite4_mutex_enter(db->mutex); if( db->xTraceDestroy ){ db->xTraceDestroy(db->pTraceArg); } db->xTrace = xTrace; db->xTraceDestroy = xDestroy; db->pTraceArg = pArg; sqlite4_mutex_leave(db->mutex); } /* ** Register a profile function. The pArg from the previously registered ** profile function is returned. ** ** A NULL profile function means that no profiling is executes. A non-NULL ** profile is a pointer to a function that is invoked at the conclusion of ** each SQL statement that is run. */ void sqlite4_profile( sqlite4 *db, void *pArg, void (*xProfile)(void*,const char*,sqlite4_uint64), void (*xDestroy)(void*) ){ void *pOld; sqlite4_mutex_enter(db->mutex); if( db->xProfileDestroy ){ db->xProfileDestroy(db->pProfileArg); } db->xProfile = xProfile; db->xProfileDestroy = xDestroy; db->pProfileArg = pArg; sqlite4_mutex_leave(db->mutex); } #endif /* SQLITE4_OMIT_TRACE */ /* ** This function returns true if main-memory should be used instead of ** a temporary file for transient pager files and statement journals. ** The value returned depends on the value of db->temp_store (runtime |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
2209 2210 2211 2212 2213 2214 2215 | if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ open_db(p); output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ | | | | 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 | if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ open_db(p); output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ sqlite4_trace(p->db, 0, 0, 0); }else{ sqlite4_trace(p->db, (void*)p->traceOut, sql_trace_callback, 0); } #endif }else if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ printf("SQLite %s %s\n" /*extra-version-info*/, sqlite4_libversion(), sqlite4_sourceid()); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
1328 1329 1330 1331 1332 1333 1334 | ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite4_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ | > > > | > > | > > | > > | 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 | ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite4_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ void sqlite4_trace( sqlite4*, void *, void(*xTrace)(void*,const char*), void(*xDestroy)(void*) ); void sqlite4_profile( sqlite4*, void *, void(*xProfile)(void*,const char*,sqlite4_uint64), void(*xDestroy)(void*) ); /* ** CAPIREF: Query Progress Callbacks ** ** ^The sqlite4_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite4_exec()] and [sqlite4_step()] for |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of VDBEs currently executing */ int writeVdbeCnt; /* Number of active VDBEs that are writing */ int vdbeExecCnt; /* Number of nested calls to VdbeExec() */ void (*xTrace)(void*,const char*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ #ifndef SQLITE4_OMIT_WAL int (*xWalCallback)(void *, sqlite4 *, const char *, int); void *pWalArg; #endif void(*xCollNeeded)(void*,sqlite4*,const char*); void(*xCollNeededDestroy)(void*); | > > | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of VDBEs currently executing */ int writeVdbeCnt; /* Number of active VDBEs that are writing */ int vdbeExecCnt; /* Number of nested calls to VdbeExec() */ void (*xTrace)(void*,const char*); /* Trace function */ void (*xTraceDestroy)(void*); /* Destructor for trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void (*xProfileDestroy)(void*); /* Profile function destructor */ void *pProfileArg; /* Argument to profile function */ #ifndef SQLITE4_OMIT_WAL int (*xWalCallback)(void *, sqlite4 *, const char *, int); void *pWalArg; #endif void(*xCollNeeded)(void*,sqlite4*,const char*); void(*xCollNeededDestroy)(void*); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 | memcpy(pDb->zProfile, zProfile, len+1); }else{ pDb->zProfile = 0; } #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( pDb->zProfile ){ pDb->interp = interp; | | | | 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | memcpy(pDb->zProfile, zProfile, len+1); }else{ pDb->zProfile = 0; } #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( pDb->zProfile ){ pDb->interp = interp; sqlite4_profile(pDb->db, (void*)pDb, DbProfileHandler, 0); }else{ sqlite4_profile(pDb->db, 0, 0, 0); } #endif } break; } /* |
︙ | ︙ | |||
2022 2023 2024 2025 2026 2027 2028 | memcpy(pDb->zTrace, zTrace, len+1); }else{ pDb->zTrace = 0; } #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( pDb->zTrace ){ pDb->interp = interp; | | | | 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 | memcpy(pDb->zTrace, zTrace, len+1); }else{ pDb->zTrace = 0; } #if !defined(SQLITE4_OMIT_TRACE) && !defined(SQLITE4_OMIT_FLOATING_POINT) if( pDb->zTrace ){ pDb->interp = interp; sqlite4_trace(pDb->db, (void*)pDb, DbTraceHandler, 0); }else{ sqlite4_trace(pDb->db, 0, 0, 0); } #endif } break; } /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 206 207 | selectB.test selectC.test selectF.test sort.test storage1.test subquery.test subquery2.test substr.test trigger1.test trigger2.test trigger3.test trigger4.test trigger5.test trigger6.test trigger7.test trigger8.test trigger9.test triggerB.test triggerC.test update.test view.test | > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | selectB.test selectC.test selectF.test sort.test storage1.test subquery.test subquery2.test substr.test trace2.test trace3.test trigger1.test trigger2.test trigger3.test trigger4.test trigger5.test trigger6.test trigger7.test trigger8.test trigger9.test triggerB.test triggerC.test update.test view.test |
︙ | ︙ |
Changes to test/test_main.c.
︙ | ︙ | |||
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 | } Tcl_ResetResult(interp); return TCL_OK; } /* End of [sqlite4_create_collation] implementation. ********************************************************************/ struct TestNeededX { Tcl_Interp *interp; Tcl_Obj *pNeeded; Tcl_Obj *pDel; }; typedef struct TestNeededX TestNeededX; | > > > | 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 | } Tcl_ResetResult(interp); return TCL_OK; } /* End of [sqlite4_create_collation] implementation. ********************************************************************/ /* ** Usage: sqlite4_collation_needed DB CALLBACK-PROC DEL-PROC */ struct TestNeededX { Tcl_Interp *interp; Tcl_Obj *pNeeded; Tcl_Obj *pDel; }; typedef struct TestNeededX TestNeededX; |
︙ | ︙ | |||
1519 1520 1521 1522 1523 1524 1525 | } Tcl_DecrRefCount(p->pNeeded); Tcl_DecrRefCount(p->pDel); sqlite4_free(0, (void *)p); } | < < < | 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 | } Tcl_DecrRefCount(p->pNeeded); Tcl_DecrRefCount(p->pDel); sqlite4_free(0, (void *)p); } static int test_collation_needed( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int nByte; /* Size of callback scripts in bytes */ |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | if( rc!=SQLITE4_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite4TestErrorName(rc), -1)); return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 | if( rc!=SQLITE4_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite4TestErrorName(rc), -1)); return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } /* End of [sqlite4_collation_needed] implementation. ********************************************************************/ /* ** Usage: sqlite4_profile DB PROFILE-CMD DEL-CMD */ struct TestProfileX { Tcl_Interp *interp; Tcl_Obj *pProfile; Tcl_Obj *pDel; }; typedef struct TestProfileX TestProfileX; static void testProfile(void *pCtx, const char *z, sqlite4_uint64 i){ TestProfileX *p = (TestProfileX *)pCtx; Tcl_Obj *pScript; int rc; pScript = Tcl_DuplicateObj(p->pProfile); Tcl_IncrRefCount(pScript); Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(z, -1)); Tcl_ListObjAppendElement(0, pScript, Tcl_NewWideIntObj(i)); rc = Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pScript); if( rc!=TCL_OK ){ Tcl_BackgroundError(p->interp); } } static void testProfileDel(void *pCtx){ TestProfileX *p = (TestProfileX*)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->pProfile); Tcl_DecrRefCount(p->pDel); sqlite4_free(0, (void *)p); } static int test_profile( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int nByte; /* Size of callback scripts in bytes */ TestProfileX *p; /* New context object */ sqlite4 *db; /* Database handle */ if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB PROFILE-CMD DEL-CMD"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; Tcl_GetStringFromObj(objv[2], &nByte); if( nByte==0 ){ sqlite4_profile(db, 0, 0, 0); }else{ p = (TestProfileX*)sqlite4_malloc(0, sizeof(TestProfileX)); p->pProfile = objv[2]; p->pDel = objv[3]; p->interp = interp; Tcl_IncrRefCount(p->pProfile); Tcl_IncrRefCount(p->pDel); sqlite4_profile(db, (void*)p, testProfile, testProfileDel); } Tcl_ResetResult(interp); return TCL_OK; } /* End of [sqlite4_profile] implementation. ********************************************************************/ /* ** Usage: sqlite4_trace DB TRACE-CMD DEL-CMD */ struct TestTraceX { Tcl_Interp *interp; Tcl_Obj *pTrace; Tcl_Obj *pDel; }; typedef struct TestTraceX TestTraceX; static void testTrace(void *pCtx, const char *z){ TestTraceX *p = (TestTraceX *)pCtx; Tcl_Obj *pScript; int rc; pScript = Tcl_DuplicateObj(p->pTrace); Tcl_IncrRefCount(pScript); Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(z, -1)); rc = Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pScript); if( rc!=TCL_OK ){ Tcl_BackgroundError(p->interp); } } static void testTraceDel(void *pCtx){ TestTraceX *p = (TestTraceX*)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->pTrace); Tcl_DecrRefCount(p->pDel); sqlite4_free(0, (void *)p); } static int test_trace( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int nByte; /* Size of callback scripts in bytes */ TestTraceX *p; /* New context object */ sqlite4 *db; /* Database handle */ if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB PROFILE-CMD DEL-CMD"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; Tcl_GetStringFromObj(objv[2], &nByte); if( nByte==0 ){ sqlite4_trace(db, 0, 0, 0); }else{ p = (TestTraceX*)sqlite4_malloc(0, sizeof(TestTraceX)); p->pTrace = objv[2]; p->pDel = objv[3]; p->interp = interp; Tcl_IncrRefCount(p->pTrace); Tcl_IncrRefCount(p->pDel); sqlite4_trace(db, (void*)p, testTrace, testTraceDel); } Tcl_ResetResult(interp); return TCL_OK; } /* End of [sqlite4_profile] implementation. ********************************************************************/ /* ** USAGE: sqlite4_create_function_v2 DB NAME NARG ENC ?SWITCHES? ** ** Available switches are: ** ** -func SCRIPT ** -step SCRIPT |
︙ | ︙ | |||
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 | { "sqlite4_column_database_name",test_stmt_utf8,(void*)sqlite4_column_database_name}, { "sqlite4_column_table_name",test_stmt_utf8,(void*)sqlite4_column_table_name}, { "sqlite4_column_origin_name",test_stmt_utf8,(void*)sqlite4_column_origin_name}, #endif { "sqlite4_create_collation", test_create_collation, 0 }, { "sqlite4_collation_needed", test_collation_needed, 0 }, { "working_64bit_int", working_64bit_int, 0 }, { "sqlite4_create_function_v2", test_create_function_v2, 0 }, /* Functions from os.h */ #ifndef SQLITE4_OMIT_UTF16 { "add_test_function", test_function, 0 }, #endif | > > | 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 | { "sqlite4_column_database_name",test_stmt_utf8,(void*)sqlite4_column_database_name}, { "sqlite4_column_table_name",test_stmt_utf8,(void*)sqlite4_column_table_name}, { "sqlite4_column_origin_name",test_stmt_utf8,(void*)sqlite4_column_origin_name}, #endif { "sqlite4_create_collation", test_create_collation, 0 }, { "sqlite4_collation_needed", test_collation_needed, 0 }, { "sqlite4_profile", test_profile, 0 }, { "sqlite4_trace", test_trace, 0 }, { "working_64bit_int", working_64bit_int, 0 }, { "sqlite4_create_function_v2", test_create_function_v2, 0 }, /* Functions from os.h */ #ifndef SQLITE4_OMIT_UTF16 { "add_test_function", test_function, 0 }, #endif |
︙ | ︙ |
Added test/trace3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 53 54 55 56 57 58 59 60 61 62 | # 2013 Jun 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the sqlite4_trace() and sqlite4_profile() # APIs. Specifically, it tests that destructor functions are invoked # correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !trace { finish_test ; return } set ::testprefix trace3 #------------------------------------------------------------------------- # The following tests verify that the profile destructor is # invoked: # # 1. When it is overridden, and # 2. When the database connection is closed. # # It would be good to test that if an error occurs within the # collation_needed() the destructor is invoked immediately (as the # documentation says). However there is currently no way to cause # sqlite4_collation_needed() to fail. sqlite4_collation_needed() # currently *always* returns SQLITE4_OK. # foreach {tn cmd} { 1 sqlite4_profile 2 sqlite4_trace } { reset_db do_test $tn.1 { set ::del 0 $cmd db abc_profile {incr ::del} set ::del } {0} do_test $tn.2 { set ::del2 0 $cmd db def_profile {incr ::del2} list $::del $::del2 } {1 0} do_test $tn.3 { db close list $::del $::del2 } {1 1} } finish_test |