modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_thread.c (about)

     1  /*
     2  ** 2007 September 9
     3  **
     4  ** The author disclaims copyright to this source code.  In place of
     5  ** a legal notice, here is a blessing:
     6  **
     7  **    May you do good and not evil.
     8  **    May you find forgiveness for yourself and forgive others.
     9  **    May you share freely, never taking more than you give.
    10  **
    11  *************************************************************************
    12  **
    13  ** This file contains the implementation of some Tcl commands used to
    14  ** test that sqlite3 database handles may be concurrently accessed by 
    15  ** multiple threads. Right now this only works on unix.
    16  */
    17  
    18  #include "sqliteInt.h"
    19  #if defined(INCLUDE_SQLITE_TCL_H)
    20  #  include "sqlite_tcl.h"
    21  #else
    22  #  include "tcl.h"
    23  #endif
    24  
    25  #if SQLITE_THREADSAFE
    26  
    27  #include <errno.h>
    28  
    29  #if !defined(_MSC_VER)
    30  #include <unistd.h>
    31  #endif
    32  
    33  /*
    34  ** One of these is allocated for each thread created by [sqlthread spawn].
    35  */
    36  typedef struct SqlThread SqlThread;
    37  struct SqlThread {
    38    Tcl_ThreadId parent;     /* Thread id of parent thread */
    39    Tcl_Interp *interp;      /* Parent interpreter */
    40    char *zScript;           /* The script to execute. */
    41    char *zVarname;          /* Varname in parent script */
    42  };
    43  
    44  /*
    45  ** A custom Tcl_Event type used by this module. When the event is
    46  ** handled, script zScript is evaluated in interpreter interp. If
    47  ** the evaluation throws an exception (returns TCL_ERROR), then the
    48  ** error is handled by Tcl_BackgroundError(). If no error occurs,
    49  ** the result is simply discarded.
    50  */
    51  typedef struct EvalEvent EvalEvent;
    52  struct EvalEvent {
    53    Tcl_Event base;          /* Base class of type Tcl_Event */
    54    char *zScript;           /* The script to execute. */
    55    Tcl_Interp *interp;      /* The interpreter to execute it in. */
    56  };
    57  
    58  static Tcl_ObjCmdProc sqlthread_proc;
    59  static Tcl_ObjCmdProc clock_seconds_proc;
    60  #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
    61  static Tcl_ObjCmdProc blocking_step_proc;
    62  static Tcl_ObjCmdProc blocking_prepare_v2_proc;
    63  #endif
    64  int Sqlitetest1_Init(Tcl_Interp *);
    65  int Sqlite3_Init(Tcl_Interp *);
    66  
    67  /* Functions from main.c */
    68  extern const char *sqlite3ErrName(int);
    69  
    70  /* Functions from test1.c */
    71  extern void *sqlite3TestTextToPtr(const char *);
    72  extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **);
    73  extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *);
    74  extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int);
    75  
    76  /*
    77  ** Handler for events of type EvalEvent.
    78  */
    79  static int SQLITE_TCLAPI tclScriptEvent(Tcl_Event *evPtr, int flags){
    80    int rc;
    81    EvalEvent *p = (EvalEvent *)evPtr;
    82    rc = Tcl_Eval(p->interp, p->zScript);
    83    if( rc!=TCL_OK ){
    84      Tcl_BackgroundError(p->interp);
    85    }
    86    UNUSED_PARAMETER(flags);
    87    return 1;
    88  }
    89  
    90  /*
    91  ** Register an EvalEvent to evaluate the script pScript in the
    92  ** parent interpreter/thread of SqlThread p.
    93  */
    94  static void postToParent(SqlThread *p, Tcl_Obj *pScript){
    95    EvalEvent *pEvent;
    96    char *zMsg;
    97    int nMsg;
    98  
    99    zMsg = Tcl_GetStringFromObj(pScript, &nMsg); 
   100    pEvent = (EvalEvent *)ckalloc(sizeof(EvalEvent)+nMsg+1);
   101    pEvent->base.nextPtr = 0;
   102    pEvent->base.proc = tclScriptEvent;
   103    pEvent->zScript = (char *)&pEvent[1];
   104    memcpy(pEvent->zScript, zMsg, nMsg+1);
   105    pEvent->interp = p->interp;
   106  
   107    Tcl_ThreadQueueEvent(p->parent, (Tcl_Event *)pEvent, TCL_QUEUE_TAIL);
   108    Tcl_ThreadAlert(p->parent);
   109  }
   110  
   111  /*
   112  ** The main function for threads created with [sqlthread spawn].
   113  */
   114  static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
   115    Tcl_Interp *interp;
   116    Tcl_Obj *pRes;
   117    Tcl_Obj *pList;
   118    int rc;
   119    SqlThread *p = (SqlThread *)pSqlThread;
   120    extern int Sqlitetest_mutex_Init(Tcl_Interp*);
   121  
   122    interp = Tcl_CreateInterp();
   123    Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
   124    Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0);
   125  #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
   126    Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0);
   127    Tcl_CreateObjCommand(interp, 
   128        "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0);
   129    Tcl_CreateObjCommand(interp, 
   130        "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0);
   131  #endif
   132    Sqlitetest1_Init(interp);
   133    Sqlitetest_mutex_Init(interp);
   134    Sqlite3_Init(interp);
   135  
   136    rc = Tcl_Eval(interp, p->zScript);
   137    pRes = Tcl_GetObjResult(interp);
   138    pList = Tcl_NewObj();
   139    Tcl_IncrRefCount(pList);
   140    Tcl_IncrRefCount(pRes);
   141  
   142    if( rc!=TCL_OK ){
   143      Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("error", -1));
   144      Tcl_ListObjAppendElement(interp, pList, pRes);
   145      postToParent(p, pList);
   146      Tcl_DecrRefCount(pList);
   147      pList = Tcl_NewObj();
   148    }
   149  
   150    Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("set", -1));
   151    Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(p->zVarname, -1));
   152    Tcl_ListObjAppendElement(interp, pList, pRes);
   153    postToParent(p, pList);
   154  
   155    ckfree((void *)p);
   156    Tcl_DecrRefCount(pList);
   157    Tcl_DecrRefCount(pRes);
   158    Tcl_DeleteInterp(interp);
   159    while( Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT) );
   160    Tcl_ExitThread(0);
   161    TCL_THREAD_CREATE_RETURN;
   162  }
   163  
   164  /*
   165  ** sqlthread spawn VARNAME SCRIPT
   166  **
   167  **     Spawn a new thread with its own Tcl interpreter and run the
   168  **     specified SCRIPT(s) in it. The thread terminates after running
   169  **     the script. The result of the script is stored in the variable
   170  **     VARNAME.
   171  **
   172  **     The caller can wait for the script to terminate using [vwait VARNAME].
   173  */
   174  static int SQLITE_TCLAPI sqlthread_spawn(
   175    ClientData clientData,
   176    Tcl_Interp *interp,
   177    int objc,
   178    Tcl_Obj *CONST objv[]
   179  ){
   180    Tcl_ThreadId x;
   181    SqlThread *pNew;
   182    int rc;
   183  
   184    int nVarname; char *zVarname;
   185    int nScript; char *zScript;
   186  
   187    /* Parameters for thread creation */
   188    const int nStack = TCL_THREAD_STACK_DEFAULT;
   189    const int flags = TCL_THREAD_NOFLAGS;
   190  
   191    assert(objc==4);
   192    UNUSED_PARAMETER(clientData);
   193    UNUSED_PARAMETER(objc);
   194  
   195    zVarname = Tcl_GetStringFromObj(objv[2], &nVarname);
   196    zScript = Tcl_GetStringFromObj(objv[3], &nScript);
   197  
   198    pNew = (SqlThread *)ckalloc(sizeof(SqlThread)+nVarname+nScript+2);
   199    pNew->zVarname = (char *)&pNew[1];
   200    pNew->zScript = (char *)&pNew->zVarname[nVarname+1];
   201    memcpy(pNew->zVarname, zVarname, nVarname+1);
   202    memcpy(pNew->zScript, zScript, nScript+1);
   203    pNew->parent = Tcl_GetCurrentThread();
   204    pNew->interp = interp;
   205  
   206    rc = Tcl_CreateThread(&x, tclScriptThread, (void *)pNew, nStack, flags);
   207    if( rc!=TCL_OK ){
   208      Tcl_AppendResult(interp, "Error in Tcl_CreateThread()", 0);
   209      ckfree((char *)pNew);
   210      return TCL_ERROR;
   211    }
   212  
   213    return TCL_OK;
   214  }
   215  
   216  /*
   217  ** sqlthread parent SCRIPT
   218  **
   219  **     This can be called by spawned threads only. It sends the specified
   220  **     script back to the parent thread for execution. The result of
   221  **     evaluating the SCRIPT is returned. The parent thread must enter
   222  **     the event loop for this to work - otherwise the caller will
   223  **     block indefinitely.
   224  **
   225  **     NOTE: At the moment, this doesn't work. FIXME.
   226  */
   227  static int SQLITE_TCLAPI sqlthread_parent(
   228    ClientData clientData,
   229    Tcl_Interp *interp,
   230    int objc,
   231    Tcl_Obj *CONST objv[]
   232  ){
   233    EvalEvent *pEvent;
   234    char *zMsg;
   235    int nMsg;
   236    SqlThread *p = (SqlThread *)clientData;
   237  
   238    assert(objc==3);
   239    UNUSED_PARAMETER(objc);
   240  
   241    if( p==0 ){
   242      Tcl_AppendResult(interp, "no parent thread", 0);
   243      return TCL_ERROR;
   244    }
   245  
   246    zMsg = Tcl_GetStringFromObj(objv[2], &nMsg);
   247    pEvent = (EvalEvent *)ckalloc(sizeof(EvalEvent)+nMsg+1);
   248    pEvent->base.nextPtr = 0;
   249    pEvent->base.proc = tclScriptEvent;
   250    pEvent->zScript = (char *)&pEvent[1];
   251    memcpy(pEvent->zScript, zMsg, nMsg+1);
   252    pEvent->interp = p->interp;
   253    Tcl_ThreadQueueEvent(p->parent, (Tcl_Event *)pEvent, TCL_QUEUE_TAIL);
   254    Tcl_ThreadAlert(p->parent);
   255  
   256    return TCL_OK;
   257  }
   258  
   259  static int xBusy(void *pArg, int nBusy){
   260    UNUSED_PARAMETER(pArg);
   261    UNUSED_PARAMETER(nBusy);
   262    sqlite3_sleep(50);
   263    return 1;             /* Try again... */
   264  }
   265  
   266  /*
   267  ** sqlthread open
   268  **
   269  **     Open a database handle and return the string representation of
   270  **     the pointer value.
   271  */
   272  static int SQLITE_TCLAPI sqlthread_open(
   273    ClientData clientData,
   274    Tcl_Interp *interp,
   275    int objc,
   276    Tcl_Obj *CONST objv[]
   277  ){
   278    int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p);
   279  
   280    const char *zFilename;
   281    sqlite3 *db;
   282    char zBuf[100];
   283    extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*);
   284  
   285    UNUSED_PARAMETER(clientData);
   286    UNUSED_PARAMETER(objc);
   287  
   288    zFilename = Tcl_GetString(objv[2]);
   289    sqlite3_open(zFilename, &db);
   290  #ifdef SQLITE_HAS_CODEC
   291    if( db && objc>=4 ){
   292      const char *zKey;
   293      int nKey;
   294      int rc;
   295      zKey = Tcl_GetStringFromObj(objv[3], &nKey);
   296      rc = sqlite3_key(db, zKey, nKey);
   297      if( rc!=SQLITE_OK ){
   298        char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db));
   299        sqlite3_close(db);
   300        Tcl_AppendResult(interp, zErrMsg, (char*)0);
   301        sqlite3_free(zErrMsg);
   302        return TCL_ERROR;
   303      }
   304    }
   305  #endif
   306    Md5_Register(db, 0, 0);
   307    sqlite3_busy_handler(db, xBusy, 0);
   308    
   309    if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
   310    Tcl_AppendResult(interp, zBuf, 0);
   311  
   312    return TCL_OK;
   313  }
   314  
   315  
   316  /*
   317  ** sqlthread open
   318  **
   319  **     Return the current thread-id (Tcl_GetCurrentThread()) cast to
   320  **     an integer.
   321  */
   322  static int SQLITE_TCLAPI sqlthread_id(
   323    ClientData clientData,
   324    Tcl_Interp *interp,
   325    int objc,
   326    Tcl_Obj *CONST objv[]
   327  ){
   328    Tcl_ThreadId id = Tcl_GetCurrentThread();
   329    Tcl_SetObjResult(interp, Tcl_NewIntObj(SQLITE_PTR_TO_INT(id)));
   330    UNUSED_PARAMETER(clientData);
   331    UNUSED_PARAMETER(objc);
   332    UNUSED_PARAMETER(objv);
   333    return TCL_OK;
   334  }
   335  
   336  
   337  /*
   338  ** Dispatch routine for the sub-commands of [sqlthread].
   339  */
   340  static int SQLITE_TCLAPI sqlthread_proc(
   341    ClientData clientData,
   342    Tcl_Interp *interp,
   343    int objc,
   344    Tcl_Obj *CONST objv[]
   345  ){
   346    struct SubCommand {
   347      char *zName;
   348      Tcl_ObjCmdProc *xProc;
   349      int nArg;
   350      char *zUsage;
   351    } aSub[] = {
   352      {"parent", sqlthread_parent, 1, "SCRIPT"},
   353      {"spawn",  sqlthread_spawn,  2, "VARNAME SCRIPT"},
   354      {"open",   sqlthread_open,   1, "DBNAME"},
   355      {"id",     sqlthread_id,     0, ""},
   356      {0, 0, 0}
   357    };
   358    struct SubCommand *pSub;
   359    int rc;
   360    int iIndex;
   361  
   362    if( objc<2 ){
   363      Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND");
   364      return TCL_ERROR;
   365    }
   366  
   367    rc = Tcl_GetIndexFromObjStruct(
   368        interp, objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iIndex
   369    );
   370    if( rc!=TCL_OK ) return rc;
   371    pSub = &aSub[iIndex];
   372  
   373    if( objc<(pSub->nArg+2) ){
   374      Tcl_WrongNumArgs(interp, 2, objv, pSub->zUsage);
   375      return TCL_ERROR;
   376    }
   377  
   378    return pSub->xProc(clientData, interp, objc, objv);
   379  }
   380  
   381  /*
   382  ** The [clock_seconds] command. This is more or less the same as the
   383  ** regular tcl [clock seconds], except that it is available in testfixture
   384  ** when linked against both Tcl 8.4 and 8.5. Because [clock seconds] is
   385  ** implemented as a script in Tcl 8.5, it is not usually available to
   386  ** testfixture.
   387  */ 
   388  static int SQLITE_TCLAPI clock_seconds_proc(
   389    ClientData clientData,
   390    Tcl_Interp *interp,
   391    int objc,
   392    Tcl_Obj *CONST objv[]
   393  ){
   394    Tcl_Time now;
   395    Tcl_GetTime(&now);
   396    Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec));
   397    UNUSED_PARAMETER(clientData);
   398    UNUSED_PARAMETER(objc);
   399    UNUSED_PARAMETER(objv);
   400    return TCL_OK;
   401  }
   402  
   403  /*************************************************************************
   404  ** This block contains the implementation of the [sqlite3_blocking_step]
   405  ** command available to threads created by [sqlthread spawn] commands. It
   406  ** is only available on UNIX for now. This is because pthread condition
   407  ** variables are used.
   408  **
   409  ** The source code for the C functions sqlite3_blocking_step(),
   410  ** blocking_step_notify() and the structure UnlockNotification is
   411  ** automatically extracted from this file and used as part of the
   412  ** documentation for the sqlite3_unlock_notify() API function. This
   413  ** should be considered if these functions are to be extended (i.e. to 
   414  ** support windows) in the future.
   415  */ 
   416  #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
   417  
   418  /* BEGIN_SQLITE_BLOCKING_STEP */
   419  /* This example uses the pthreads API */
   420  #include <pthread.h>
   421  
   422  /*
   423  ** A pointer to an instance of this structure is passed as the user-context
   424  ** pointer when registering for an unlock-notify callback.
   425  */
   426  typedef struct UnlockNotification UnlockNotification;
   427  struct UnlockNotification {
   428    int fired;                         /* True after unlock event has occurred */
   429    pthread_cond_t cond;               /* Condition variable to wait on */
   430    pthread_mutex_t mutex;             /* Mutex to protect structure */
   431  };
   432  
   433  /*
   434  ** This function is an unlock-notify callback registered with SQLite.
   435  */
   436  static void unlock_notify_cb(void **apArg, int nArg){
   437    int i;
   438    for(i=0; i<nArg; i++){
   439      UnlockNotification *p = (UnlockNotification *)apArg[i];
   440      pthread_mutex_lock(&p->mutex);
   441      p->fired = 1;
   442      pthread_cond_signal(&p->cond);
   443      pthread_mutex_unlock(&p->mutex);
   444    }
   445  }
   446  
   447  /*
   448  ** This function assumes that an SQLite API call (either sqlite3_prepare_v2() 
   449  ** or sqlite3_step()) has just returned SQLITE_LOCKED. The argument is the
   450  ** associated database connection.
   451  **
   452  ** This function calls sqlite3_unlock_notify() to register for an 
   453  ** unlock-notify callback, then blocks until that callback is delivered 
   454  ** and returns SQLITE_OK. The caller should then retry the failed operation.
   455  **
   456  ** Or, if sqlite3_unlock_notify() indicates that to block would deadlock 
   457  ** the system, then this function returns SQLITE_LOCKED immediately. In 
   458  ** this case the caller should not retry the operation and should roll 
   459  ** back the current transaction (if any).
   460  */
   461  static int wait_for_unlock_notify(sqlite3 *db){
   462    int rc;
   463    UnlockNotification un;
   464  
   465    /* Initialize the UnlockNotification structure. */
   466    un.fired = 0;
   467    pthread_mutex_init(&un.mutex, 0);
   468    pthread_cond_init(&un.cond, 0);
   469  
   470    /* Register for an unlock-notify callback. */
   471    rc = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)&un);
   472    assert( rc==SQLITE_LOCKED || rc==SQLITE_OK );
   473  
   474    /* The call to sqlite3_unlock_notify() always returns either SQLITE_LOCKED 
   475    ** or SQLITE_OK. 
   476    **
   477    ** If SQLITE_LOCKED was returned, then the system is deadlocked. In this
   478    ** case this function needs to return SQLITE_LOCKED to the caller so 
   479    ** that the current transaction can be rolled back. Otherwise, block
   480    ** until the unlock-notify callback is invoked, then return SQLITE_OK.
   481    */
   482    if( rc==SQLITE_OK ){
   483      pthread_mutex_lock(&un.mutex);
   484      if( !un.fired ){
   485        pthread_cond_wait(&un.cond, &un.mutex);
   486      }
   487      pthread_mutex_unlock(&un.mutex);
   488    }
   489  
   490    /* Destroy the mutex and condition variables. */
   491    pthread_cond_destroy(&un.cond);
   492    pthread_mutex_destroy(&un.mutex);
   493  
   494    return rc;
   495  }
   496  
   497  /*
   498  ** This function is a wrapper around the SQLite function sqlite3_step().
   499  ** It functions in the same way as step(), except that if a required
   500  ** shared-cache lock cannot be obtained, this function may block waiting for
   501  ** the lock to become available. In this scenario the normal API step()
   502  ** function always returns SQLITE_LOCKED.
   503  **
   504  ** If this function returns SQLITE_LOCKED, the caller should rollback
   505  ** the current transaction (if any) and try again later. Otherwise, the
   506  ** system may become deadlocked.
   507  */
   508  int sqlite3_blocking_step(sqlite3_stmt *pStmt){
   509    int rc;
   510    while( SQLITE_LOCKED==(rc = sqlite3_step(pStmt)) ){
   511      rc = wait_for_unlock_notify(sqlite3_db_handle(pStmt));
   512      if( rc!=SQLITE_OK ) break;
   513      sqlite3_reset(pStmt);
   514    }
   515    return rc;
   516  }
   517  
   518  /*
   519  ** This function is a wrapper around the SQLite function sqlite3_prepare_v2().
   520  ** It functions in the same way as prepare_v2(), except that if a required
   521  ** shared-cache lock cannot be obtained, this function may block waiting for
   522  ** the lock to become available. In this scenario the normal API prepare_v2()
   523  ** function always returns SQLITE_LOCKED.
   524  **
   525  ** If this function returns SQLITE_LOCKED, the caller should rollback
   526  ** the current transaction (if any) and try again later. Otherwise, the
   527  ** system may become deadlocked.
   528  */
   529  int sqlite3_blocking_prepare_v2(
   530    sqlite3 *db,              /* Database handle. */
   531    const char *zSql,         /* UTF-8 encoded SQL statement. */
   532    int nSql,                 /* Length of zSql in bytes. */
   533    sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
   534    const char **pz           /* OUT: End of parsed string */
   535  ){
   536    int rc;
   537    while( SQLITE_LOCKED==(rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, pz)) ){
   538      rc = wait_for_unlock_notify(db);
   539      if( rc!=SQLITE_OK ) break;
   540    }
   541    return rc;
   542  }
   543  /* END_SQLITE_BLOCKING_STEP */
   544  
   545  /*
   546  ** Usage: sqlite3_blocking_step STMT
   547  **
   548  ** Advance the statement to the next row.
   549  */
   550  static int SQLITE_TCLAPI blocking_step_proc(
   551    void * clientData,
   552    Tcl_Interp *interp,
   553    int objc,
   554    Tcl_Obj *CONST objv[]
   555  ){
   556  
   557    sqlite3_stmt *pStmt;
   558    int rc;
   559  
   560    if( objc!=2 ){
   561      Tcl_WrongNumArgs(interp, 1, objv, "STMT");
   562      return TCL_ERROR;
   563    }
   564  
   565    pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
   566    rc = sqlite3_blocking_step(pStmt);
   567  
   568    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), 0);
   569    return TCL_OK;
   570  }
   571  
   572  /*
   573  ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar?
   574  ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar?
   575  */
   576  static int SQLITE_TCLAPI blocking_prepare_v2_proc(
   577    void * clientData,
   578    Tcl_Interp *interp,
   579    int objc,
   580    Tcl_Obj *CONST objv[]
   581  ){
   582    sqlite3 *db;
   583    const char *zSql;
   584    int bytes;
   585    const char *zTail = 0;
   586    sqlite3_stmt *pStmt = 0;
   587    char zBuf[50];
   588    int rc;
   589    int isBlocking = !(clientData==0);
   590  
   591    if( objc!=5 && objc!=4 ){
   592      Tcl_AppendResult(interp, "wrong # args: should be \"", 
   593         Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
   594      return TCL_ERROR;
   595    }
   596    if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
   597    zSql = Tcl_GetString(objv[2]);
   598    if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
   599  
   600    if( isBlocking ){
   601      rc = sqlite3_blocking_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
   602    }else{
   603      rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
   604    }
   605  
   606    assert(rc==SQLITE_OK || pStmt==0);
   607    if( zTail && objc>=5 ){
   608      if( bytes>=0 ){
   609        bytes = bytes - (zTail-zSql);
   610      }
   611      Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
   612    }
   613    if( rc!=SQLITE_OK ){
   614      assert( pStmt==0 );
   615      sqlite3_snprintf(sizeof(zBuf), zBuf, "%s ", (char *)sqlite3ErrName(rc));
   616      Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
   617      return TCL_ERROR;
   618    }
   619  
   620    if( pStmt ){
   621      if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
   622      Tcl_AppendResult(interp, zBuf, 0);
   623    }
   624    return TCL_OK;
   625  }
   626  
   627  #endif /* SQLITE_OS_UNIX && SQLITE_ENABLE_UNLOCK_NOTIFY */
   628  /*
   629  ** End of implementation of [sqlite3_blocking_step].
   630  ************************************************************************/
   631  
   632  /*
   633  ** Register commands with the TCL interpreter.
   634  */
   635  int SqlitetestThread_Init(Tcl_Interp *interp){
   636    Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0);
   637    Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
   638  #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
   639    Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0);
   640    Tcl_CreateObjCommand(interp, 
   641        "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0);
   642    Tcl_CreateObjCommand(interp, 
   643        "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0);
   644  #endif
   645    return TCL_OK;
   646  }
   647  #else
   648  int SqlitetestThread_Init(Tcl_Interp *interp){
   649    return TCL_OK;
   650  }
   651  #endif