summaryrefslogtreecommitdiffstats
path: root/ext/misc/blobio.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/misc/blobio.c')
-rw-r--r--ext/misc/blobio.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/ext/misc/blobio.c b/ext/misc/blobio.c
new file mode 100644
index 0000000..3a1ee84
--- /dev/null
+++ b/ext/misc/blobio.c
@@ -0,0 +1,152 @@
+/*
+** 2019-03-30
+**
+** 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.
+**
+******************************************************************************
+**
+** An SQL function that uses the incremental BLOB I/O mechanism of SQLite
+** to read or write part of a blob. This is intended for debugging use
+** in the CLI.
+**
+** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N)
+**
+** Returns N bytes of the blob starting at OFFSET.
+**
+** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA)
+**
+** NEWDATA must be a blob. The content of NEWDATA overwrites the
+** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning
+** at OFFSET bytes into the blob.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+static void readblobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_blob *pBlob = 0;
+ const char *zSchema;
+ const char *zTable;
+ const char *zColumn;
+ sqlite3_int64 iRowid;
+ int iOfst;
+ unsigned char *aData;
+ int nData;
+ sqlite3 *db;
+ int rc;
+
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ zTable = (const char*)sqlite3_value_text(argv[1]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad table name", -1);
+ return;
+ }
+ zColumn = (const char*)sqlite3_value_text(argv[2]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad column name", -1);
+ return;
+ }
+ iRowid = sqlite3_value_int64(argv[3]);
+ iOfst = sqlite3_value_int(argv[4]);
+ nData = sqlite3_value_int(argv[5]);
+ if( nData<=0 ) return;
+ aData = sqlite3_malloc64( nData+1 );
+ if( aData==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ db = sqlite3_context_db_handle(context);
+ rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob);
+ if( rc ){
+ sqlite3_free(aData);
+ sqlite3_result_error(context, "cannot open BLOB pointer", -1);
+ return;
+ }
+ rc = sqlite3_blob_read(pBlob, aData, nData, iOfst);
+ sqlite3_blob_close(pBlob);
+ if( rc ){
+ sqlite3_free(aData);
+ sqlite3_result_error(context, "BLOB read failed", -1);
+ }else{
+ sqlite3_result_blob(context, aData, nData, sqlite3_free);
+ }
+}
+
+static void writeblobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_blob *pBlob = 0;
+ const char *zSchema;
+ const char *zTable;
+ const char *zColumn;
+ sqlite3_int64 iRowid;
+ int iOfst;
+ unsigned char *aData;
+ int nData;
+ sqlite3 *db;
+ int rc;
+
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ zTable = (const char*)sqlite3_value_text(argv[1]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad table name", -1);
+ return;
+ }
+ zColumn = (const char*)sqlite3_value_text(argv[2]);
+ if( zTable==0 ){
+ sqlite3_result_error(context, "bad column name", -1);
+ return;
+ }
+ iRowid = sqlite3_value_int64(argv[3]);
+ iOfst = sqlite3_value_int(argv[4]);
+ if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){
+ sqlite3_result_error(context, "6th argument must be a BLOB", -1);
+ return;
+ }
+ nData = sqlite3_value_bytes(argv[5]);
+ aData = (unsigned char *)sqlite3_value_blob(argv[5]);
+ db = sqlite3_context_db_handle(context);
+ rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob);
+ if( rc ){
+ sqlite3_result_error(context, "cannot open BLOB pointer", -1);
+ return;
+ }
+ rc = sqlite3_blob_write(pBlob, aData, nData, iOfst);
+ sqlite3_blob_close(pBlob);
+ if( rc ){
+ sqlite3_result_error(context, "BLOB write failed", -1);
+ }
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_blobio_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
+ readblobFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
+ writeblobFunc, 0, 0);
+ }
+ return rc;
+}