SQLite Forum

PSTOKEN extension
Login

PSTOKEN extension

(1) By anonymous on 2020-12-24 22:45:03 [source]

/*
  The below is a public domain SQLite extension for writing PostScript tokens as output.
  This might be useful if you want to export data from SQLite to use with PostScript, e.g. to make graphics.
  (The SQLite command shell can already output many other formats, but not PostScript, so here it is in case you want to use SQLite with PostScript.)
  Note that the PostScript interpreter may have limits to numeric values and lengths of strings which are less than SQLite.
  Write PSTOKEN(...) replace ... with any number of arguments.
  It is written as a executable array (procedure) token, which may be read by the "token" operator.
  (You may also write something like [(%stdin) run] if you want to just put it into an array.)
  Strings and blobs are both written as PostScript strings; if you need to distinguish it, you must add another column.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3ext.h"

static const sqlite3_api_routines*sqlite3_api;

static void fn_pstoken(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
  sqlite3_str*str=sqlite3_str_new(sqlite3_context_db_handle(cxt));
  const unsigned char*c;
  int i,j,n;
  sqlite3_str_appendchar(str,1,'{');
  for(i=0;i<argc;i++) switch(sqlite3_value_type(argv[i])) {
    case SQLITE_NULL:
      sqlite3_str_append(str," //null",7);
      break;
    case SQLITE_FLOAT:
      sqlite3_str_appendf(str," %!f",sqlite3_value_double(argv[i]));
      break;
    case SQLITE_INTEGER:
      sqlite3_str_appendf(str," %lld",sqlite3_value_int64(argv[i]));
      break;
    case SQLITE_TEXT:
      c=sqlite3_value_text(argv[i]);
      n=sqlite3_value_bytes(argv[i]);
      sqlite3_str_append(str," (",2);
      for(j=0;j<n;j++) {
        if(c[j]=='(' || c[j]==')' || c[j]=='\\') sqlite3_str_appendchar(str,1,'\\');
        if(c[j]>=32 && c[j]<127) sqlite3_str_appendchar(str,1,c[j]); else sqlite3_str_appendf(str,"\\%03o",c[j]);
      }
      sqlite3_str_appendchar(str,1,')');
      break;
    case SQLITE_BLOB:
      c=sqlite3_value_blob(argv[i]);
      n=sqlite3_value_bytes(argv[i]);
      sqlite3_str_append(str," <",2);
      for(j=0;j<n;j++) sqlite3_str_appendf(str,"%02X",c[j]);
      sqlite3_str_appendchar(str,1,'>');
      break;
  }
  sqlite3_str_append(str," }",2);
  if(i=sqlite3_str_errcode(str)) {
    sqlite3_free(sqlite3_str_finish(str));
    if(i==SQLITE_TOOBIG) sqlite3_result_error_toobig(cxt);
    if(i==SQLITE_NOMEM) sqlite3_result_error_nomem(cxt);
  } else {
    sqlite3_result_text(cxt,sqlite3_str_finish(str),-1,sqlite3_free);
  }
}

int sqlite3_extension_init(sqlite3*db,const char**err,const struct sqlite3_api_routines*api) {
  sqlite3_api=api;
  sqlite3_create_function(db,"PSTOKEN",-1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_pstoken,0,0);
  return SQLITE_OK;
}