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

     1  /*
     2  ** 2014 October 30
     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  */
    14  #include "sqliteInt.h"
    15  #if defined(INCLUDE_SQLITE_TCL_H)
    16  #  include "sqlite_tcl.h"
    17  #else
    18  #  include "tcl.h"
    19  #endif
    20  #include <stdlib.h>
    21  #include <string.h>
    22  #include <assert.h>
    23  #ifndef SQLITE_OMIT_INCRBLOB
    24  
    25  /* These functions are implemented in main.c. */
    26  extern const char *sqlite3ErrName(int);
    27  
    28  /* From test1.c: */
    29  extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
    30  extern void *sqlite3TestTextToPtr(const char *z);
    31  
    32  /*
    33  ** Return a pointer to a buffer containing a text representation of the
    34  ** pointer passed as the only argument. The original pointer may be extracted
    35  ** from the text using sqlite3TestTextToPtr().
    36  */
    37  static char *ptrToText(void *p){
    38    static char buf[100];
    39    sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p);
    40    return buf;
    41  }
    42  
    43  /*
    44  ** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl
    45  ** object passed as the second argument. If successful, set *ppBlob to
    46  ** point to the blob handle and return TCL_OK. Otherwise, store an error
    47  ** message in the tcl interpreter and return TCL_ERROR. The final value
    48  ** of *ppBlob is undefined in this case.
    49  **
    50  ** If the object contains a string that begins with "incrblob_", then it
    51  ** is assumed to be the name of a Tcl channel opened using the [db incrblob] 
    52  ** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer 
    53  ** encoded using the ptrToText() routine or similar.
    54  */
    55  static int blobHandleFromObj(
    56    Tcl_Interp *interp, 
    57    Tcl_Obj *pObj,
    58    sqlite3_blob **ppBlob
    59  ){
    60    char *z;
    61    int n;
    62  
    63    z = Tcl_GetStringFromObj(pObj, &n);
    64    if( n==0 ){
    65      *ppBlob = 0;
    66    }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){
    67      int notUsed;
    68      Tcl_Channel channel;
    69      ClientData instanceData;
    70      
    71      channel = Tcl_GetChannel(interp, z, &notUsed);
    72      if( !channel ) return TCL_ERROR;
    73  
    74      Tcl_Flush(channel);
    75      Tcl_Seek(channel, 0, SEEK_SET);
    76  
    77      instanceData = Tcl_GetChannelInstanceData(channel);
    78      *ppBlob = *((sqlite3_blob **)instanceData);
    79    }else{
    80      *ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z);
    81    }
    82  
    83    return TCL_OK;
    84  }
    85  
    86  /*
    87  ** Like Tcl_GetString(), except that if the string is 0 bytes in size, a
    88  ** NULL Pointer is returned.
    89  */
    90  static char *blobStringFromObj(Tcl_Obj *pObj){
    91    int n;
    92    char *z;
    93    z = Tcl_GetStringFromObj(pObj, &n);
    94    return (n ? z : 0);
    95  }
    96  
    97  /*
    98  ** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME
    99  **
   100  ** Tcl test harness for the sqlite3_blob_open() function.
   101  */
   102  static int SQLITE_TCLAPI test_blob_open(
   103    ClientData clientData,          /* Not used */
   104    Tcl_Interp *interp,             /* Calling TCL interpreter */
   105    int objc,                       /* Number of arguments */
   106    Tcl_Obj *CONST objv[]           /* Command arguments */
   107  ){
   108    sqlite3 *db;
   109    const char *zDb;
   110    const char *zTable;
   111    const char *zColumn;
   112    Tcl_WideInt iRowid;
   113    int flags;
   114    const char *zVarname;
   115    int nVarname;
   116  
   117    sqlite3_blob *pBlob = (sqlite3_blob*)&flags;   /* Non-zero initialization */
   118    int rc;
   119  
   120    if( objc!=8 ){
   121      const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME";
   122      Tcl_WrongNumArgs(interp, 1, objv, zUsage);
   123      return TCL_ERROR;
   124    }
   125    if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
   126    zDb = Tcl_GetString(objv[2]);
   127    zTable = blobStringFromObj(objv[3]);
   128    zColumn = Tcl_GetString(objv[4]);
   129    if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR;
   130    if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR;
   131    zVarname = Tcl_GetStringFromObj(objv[7], &nVarname);
   132  
   133    if( nVarname>0 ){
   134      rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob);
   135      Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0);
   136    }else{
   137      rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0);
   138    }
   139  
   140    if( rc==SQLITE_OK ){
   141      Tcl_ResetResult(interp);
   142    }else{
   143      Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
   144      return TCL_ERROR;
   145    }
   146    return TCL_OK;
   147  }
   148  
   149  
   150  /*
   151  ** sqlite3_blob_close  HANDLE
   152  */
   153  static int SQLITE_TCLAPI test_blob_close(
   154    ClientData clientData, /* Not used */
   155    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   156    int objc,              /* Number of arguments */
   157    Tcl_Obj *CONST objv[]  /* Command arguments */
   158  ){
   159    sqlite3_blob *pBlob;
   160    int rc;
   161    
   162    if( objc!=2 ){
   163      Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
   164      return TCL_ERROR;
   165    }
   166  
   167    if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
   168    rc = sqlite3_blob_close(pBlob);
   169  
   170    if( rc ){
   171      Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
   172    }else{
   173      Tcl_ResetResult(interp);
   174    }
   175    return TCL_OK;
   176  }
   177  
   178  /*
   179  ** sqlite3_blob_bytes  HANDLE
   180  */
   181  static int SQLITE_TCLAPI test_blob_bytes(
   182    ClientData clientData, /* Not used */
   183    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   184    int objc,              /* Number of arguments */
   185    Tcl_Obj *CONST objv[]  /* Command arguments */
   186  ){
   187    sqlite3_blob *pBlob;
   188    int nByte;
   189    
   190    if( objc!=2 ){
   191      Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
   192      return TCL_ERROR;
   193    }
   194  
   195    if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
   196    nByte = sqlite3_blob_bytes(pBlob);
   197    Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte));
   198  
   199    return TCL_OK;
   200  }
   201  
   202  /*
   203  ** sqlite3_blob_read  CHANNEL OFFSET N
   204  **
   205  **   This command is used to test the sqlite3_blob_read() in ways that
   206  **   the Tcl channel interface does not. The first argument should
   207  **   be the name of a valid channel created by the [incrblob] method
   208  **   of a database handle. This function calls sqlite3_blob_read()
   209  **   to read N bytes from offset OFFSET from the underlying SQLite
   210  **   blob handle.
   211  **
   212  **   On success, a byte-array object containing the read data is 
   213  **   returned. On failure, the interpreter result is set to the
   214  **   text representation of the returned error code (i.e. "SQLITE_NOMEM")
   215  **   and a Tcl exception is thrown.
   216  */
   217  static int SQLITE_TCLAPI test_blob_read(
   218    ClientData clientData, /* Not used */
   219    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   220    int objc,              /* Number of arguments */
   221    Tcl_Obj *CONST objv[]  /* Command arguments */
   222  ){
   223    sqlite3_blob *pBlob;
   224    int nByte;
   225    int iOffset;
   226    unsigned char *zBuf = 0;
   227    int rc;
   228    
   229    if( objc!=4 ){
   230      Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
   231      return TCL_ERROR;
   232    }
   233  
   234    if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
   235    if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
   236     || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte)
   237    ){ 
   238      return TCL_ERROR;
   239    }
   240  
   241    if( nByte>0 ){
   242      zBuf = (unsigned char *)Tcl_AttemptAlloc(nByte);
   243      if( zBuf==0 ){
   244        Tcl_AppendResult(interp, "out of memory in " __FILE__, 0);
   245        return TCL_ERROR;
   246      }
   247    }
   248    rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
   249    if( rc==SQLITE_OK ){
   250      Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte));
   251    }else{
   252      Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   253    }
   254    Tcl_Free((char *)zBuf);
   255  
   256    return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
   257  }
   258  
   259  /*
   260  ** sqlite3_blob_write HANDLE OFFSET DATA ?NDATA?
   261  **
   262  **   This command is used to test the sqlite3_blob_write() in ways that
   263  **   the Tcl channel interface does not. The first argument should
   264  **   be the name of a valid channel created by the [incrblob] method
   265  **   of a database handle. This function calls sqlite3_blob_write()
   266  **   to write the DATA byte-array to the underlying SQLite blob handle.
   267  **   at offset OFFSET.
   268  **
   269  **   On success, an empty string is returned. On failure, the interpreter
   270  **   result is set to the text representation of the returned error code 
   271  **   (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
   272  */
   273  static int SQLITE_TCLAPI test_blob_write(
   274    ClientData clientData, /* Not used */
   275    Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
   276    int objc,              /* Number of arguments */
   277    Tcl_Obj *CONST objv[]  /* Command arguments */
   278  ){
   279    sqlite3_blob *pBlob;
   280    int iOffset;
   281    int rc;
   282  
   283    unsigned char *zBuf;
   284    int nBuf;
   285    
   286    if( objc!=4 && objc!=5 ){
   287      Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?");
   288      return TCL_ERROR;
   289    }
   290  
   291    if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
   292    if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ 
   293      return TCL_ERROR;
   294    }
   295  
   296    zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
   297    if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){
   298      return TCL_ERROR;
   299    }
   300    rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
   301    if( rc!=SQLITE_OK ){
   302      Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   303    }
   304  
   305    return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
   306  }
   307  #endif /* SQLITE_OMIT_INCRBLOB */
   308  
   309  /*
   310  ** Register commands with the TCL interpreter.
   311  */
   312  int Sqlitetest_blob_Init(Tcl_Interp *interp){
   313  #ifndef SQLITE_OMIT_INCRBLOB
   314    static struct {
   315       char *zName;
   316       Tcl_ObjCmdProc *xProc;
   317    } aObjCmd[] = {
   318       { "sqlite3_blob_open",            test_blob_open        },
   319       { "sqlite3_blob_close",           test_blob_close       },
   320       { "sqlite3_blob_bytes",           test_blob_bytes       },
   321       { "sqlite3_blob_read",            test_blob_read        },
   322       { "sqlite3_blob_write",           test_blob_write       },
   323    };
   324    int i;
   325    for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
   326      Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
   327    }
   328  #endif /* SQLITE_OMIT_INCRBLOB */
   329    return TCL_OK;
   330  }