wasCSharpSQLite – Rev

Subversion Repositories:
Rev:
using System;
using System.Diagnostics;
using System.Text;

using i64 = System.Int64;
using u8 = System.Byte;

namespace Community.CsharpSqlite
{
#if TCLSH
  using tcl.lang;
  using sqlite_int64 = System.Int64;
  using sqlite3_stmt = Sqlite3.Vdbe;
  using sqlite3_value = Sqlite3.Mem;
  using Tcl_Interp = tcl.lang.Interp;
  using Tcl_Obj = tcl.lang.TclObject;
  using ClientData = System.Object;

  public partial class Sqlite3
  {
    /*
    ** 2006 June 10
    **
    ** 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.
    **
    *************************************************************************
    ** Code for testing the virtual table interfaces.  This code
    ** is not included in the SQLite library.  It is used for automated
    ** testing of the SQLite library.
    *************************************************************************
    ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
    ** C#-SQLite is an independent reimplementation of the SQLite software library
    **
    ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
    **
    *************************************************************************
    */

    /* The code in this file defines a sqlite3 virtual-table module that
    ** provides a read-only view of the current database schema. There is one
    ** row in the schema table for each column in the database schema.
    */
    //#define SCHEMA \
    //"CREATE TABLE x("                                                            \
    //  "database,"          /* Name of database (i.e. main, temp etc.) */         \
    //  "tablename,"         /* Name of table */                                   \
    //  "cid,"               /* Column number (from left-to-right, 0 upward) */    \
    //  "name,"              /* Column name */                                     \
    //  "type,"              /* Specified type (i.e. VARCHAR(32)) */               \
    //  "not_null,"          /* Boolean. True if NOT NULL was specified */         \
    //  "dflt_value,"        /* Default value for this column */                   \
    //  "pk"                 /* True if this column is part of the primary key */  \
    //")"
    const string SCHEMA = "CREATE TABLE x(" +
      "database," +
      "tablename," +
      "cid," +
      "name," +
      "type," +
      "not_null," +
      "dflt_value," +
      "pk" +
    ")";

    /* If SQLITE_TEST is defined this code is preprocessed for use as part
** of the sqlite test binary "testfixture". Otherwise it is preprocessed
** to be compiled into an sqlite dynamic extension.
*/
    //#if SQLITE_TEST
    //  #include "sqliteInt.h"
    //  #include "tcl.h"
    //#else
    //  #include "sqlite3ext.h"
    //  SQLITE_EXTENSION_INIT1
    //#endif

    //#include <stdlib.h>
    //#include <string.h>
    //#include <Debug.Assert.h>

    //typedef struct schema_vtab schema_vtab;
    //typedef struct schema_cursor schema_cursor;

    /* A schema table object */
    class schema_vtab : sqlite3_vtab
    {
      //  sqlite3_vtab base;
      public sqlite3 db;
    };

    /* A schema table cursor object */
    class schema_cursor : sqlite3_vtab_cursor
    {
      //sqlite3_vtab_cursor base;
      public sqlite3_stmt pDbList;
      public sqlite3_stmt pTableList;
      public sqlite3_stmt pColumnList;
      public int rowid;
    };

    /*
    ** None of this works unless we have virtual tables.
    */
#if !SQLITE_OMIT_VIRTUALTABLE

    /*
** Table destructor for the schema module.
*/
    static int schemaDestroy( ref object pVtab )
    {
      pVtab = null;//sqlite3_free(pVtab);
      return 0;
    }

    /*
    ** Table constructor for the schema module.
    */
    static int schemaCreate(
      sqlite3 db,
      object pAux,
      int argc,
      string[] argv,
      out sqlite3_vtab ppVtab,
      out string pzErr
    )
    {
      int rc = SQLITE_NOMEM;
      schema_vtab pVtab = new schema_vtab();//sqlite3_malloc(sizeof(schema_vtab));
      if ( pVtab != null )
      {
        //memset(pVtab, 0, sizeof(schema_vtab));
        pVtab.db = db;
#if !SQLITE_OMIT_VIRTUALTABLE
        rc = sqlite3_declare_vtab( db, SCHEMA );
#endif
      }
      ppVtab = (sqlite3_vtab)pVtab;
      pzErr = "";
      return rc;
    }

    /*
    ** Open a new cursor on the schema table.
    */
    static int schemaOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
    {
      int rc = SQLITE_NOMEM;
      schema_cursor pCur;
      pCur = new schema_cursor();//pCur = sqlite3_malloc(sizeof(schema_cursor));
      //if ( pCur != null )
      //{
        //memset(pCur, 0, sizeof(schema_cursor));
        ppCursor = (sqlite3_vtab_cursor)pCur;
        rc = SQLITE_OK;
      //}
      return rc;
    }

    /*
    ** Close a schema table cursor.
    */
    static int schemaClose( ref sqlite3_vtab_cursor cur )
    {
      schema_cursor pCur = (schema_cursor)cur;
      sqlite3_finalize( pCur.pDbList );
      sqlite3_finalize( pCur.pTableList );
      sqlite3_finalize( pCur.pColumnList );
      //sqlite3_free( pCur );
      cur = null;//
      return SQLITE_OK;
    }

    /*
    ** Retrieve a column of data.
    */
    static int schemaColumn( sqlite3_vtab_cursor cur, sqlite3_context ctx, int i )
    {
      schema_cursor pCur = (schema_cursor)cur;
      switch ( i )
      {
        case 0:
          sqlite3_result_value( ctx, sqlite3_column_value( pCur.pDbList, 1 ) );
          break;
        case 1:
          sqlite3_result_value( ctx, sqlite3_column_value( pCur.pTableList, 0 ) );
          break;
        default:
          sqlite3_result_value( ctx, sqlite3_column_value( pCur.pColumnList, i - 2 ) );
          break;
      }
      return SQLITE_OK;
    }

    /*
    ** Retrieve the current rowid.
    */
    static int schemaRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
    {
      schema_cursor pCur = (schema_cursor)cur;
      pRowid = pCur.rowid;
      return SQLITE_OK;
    }

    static int finalize( ref sqlite3_stmt ppStmt )
    {
      int rc = sqlite3_finalize( ppStmt );
      ppStmt = null;
      return rc;
    }

    static int schemaEof( sqlite3_vtab_cursor cur )
    {
      schema_cursor pCur = (schema_cursor)cur;
      return ( pCur.pDbList != null ? 0 : 1 );
    }

    /*
    ** Advance the cursor to the next row.
    */
    static int schemaNext( sqlite3_vtab_cursor cur )
    {
      int rc = SQLITE_OK;
      schema_cursor pCur = (schema_cursor)cur;
      schema_vtab pVtab = (schema_vtab)( cur.pVtab );
      string zSql = null;

      while ( null == pCur.pColumnList || SQLITE_ROW != sqlite3_step( pCur.pColumnList ) )
      {
        if ( SQLITE_OK != ( rc = finalize( ref pCur.pColumnList ) ) )
          goto next_exit;

        while ( null == pCur.pTableList || SQLITE_ROW != sqlite3_step( pCur.pTableList ) )
        {
          if ( SQLITE_OK != ( rc = finalize( ref pCur.pTableList ) ) )
            goto next_exit;

          Debug.Assert( pCur.pDbList !=null);
          while ( SQLITE_ROW != sqlite3_step( pCur.pDbList ) )
          {
            rc = finalize( ref pCur.pDbList );
            goto next_exit;
          }

          /* Set zSql to the SQL to pull the list of tables from the 
          ** sqlite_master (or sqlite_temp_master) table of the database
          ** identfied by the row pointed to by the SQL statement pCur.pDbList
          ** (iterating through a "PRAGMA database_list;" statement).
          */
          if ( sqlite3_column_int( pCur.pDbList, 0 ) == 1 )
          {
            zSql = sqlite3_mprintf(
                "SELECT name FROM sqlite_temp_master WHERE type='table'"
            );
          }
          else
          {
            sqlite3_stmt pDbList = pCur.pDbList;
            zSql = sqlite3_mprintf(
                "SELECT name FROM %Q.sqlite_master WHERE type='table'",
                 sqlite3_column_text( pDbList, 1 )
            );
          }
          //if( !zSql ){
          //  rc = SQLITE_NOMEM;
          //  goto next_exit;
          //}
          rc = sqlite3_prepare( pVtab.db, zSql, -1, ref pCur.pTableList, 0 );
          //sqlite3_free(zSql);
          if ( rc != SQLITE_OK )
            goto next_exit;
        }

        /* Set zSql to the SQL to the table_info pragma for the table currently
        ** identified by the rows pointed to by statements pCur.pDbList and
        ** pCur.pTableList.
        */
        zSql = sqlite3_mprintf( "PRAGMA %Q.table_info(%Q)",
            sqlite3_column_text( pCur.pDbList, 1 ),
            sqlite3_column_text( pCur.pTableList, 0 )
        );

        //if( !Sql ){
        //  rc = SQLITE_NOMEM;
        //  goto next_exit;
        //}
        rc = sqlite3_prepare( pVtab.db, zSql, -1, ref pCur.pColumnList, 0 );
        //sqlite3_free(zSql);
        if ( rc != SQLITE_OK )
          goto next_exit;
      }
      pCur.rowid++;

next_exit:
      /* TODO: Handle rc */
      return rc;
    }

    /*
    ** Reset a schema table cursor.
    */
    static int schemaFilter(
      sqlite3_vtab_cursor pVtabCursor,
      int idxNum,
      string idxStr,
      int argc,
      sqlite3_value[] argv
    )
    {
      int rc;
      schema_vtab pVtab = (schema_vtab)( pVtabCursor.pVtab );
      schema_cursor pCur = (schema_cursor)pVtabCursor;
      pCur.rowid = 0;
      finalize( ref pCur.pTableList );
      finalize( ref pCur.pColumnList );
      finalize( ref pCur.pDbList );
      rc = sqlite3_prepare( pVtab.db, "PRAGMA database_list", -1, ref pCur.pDbList, 0 );
      return ( rc == SQLITE_OK ? schemaNext( pVtabCursor ) : rc );
    }

    /*
    ** Analyse the WHERE condition.
    */
    static int schemaBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
    {
      return SQLITE_OK;
    }

    /*
    ** A virtual table module that merely echos method calls into TCL
    ** variables.
    */
    static sqlite3_module schemaModule = new sqlite3_module(
      0,                           /* iVersion */
      schemaCreate,
      schemaCreate,
      schemaBestIndex,
      schemaDestroy,
      schemaDestroy,
      schemaOpen,                  /* xOpen - open a cursor */
      schemaClose,                 /* xClose - close a cursor */
      schemaFilter,                /* xFilter - configure scan constraints */
      schemaNext,                  /* xNext - advance a cursor */
      schemaEof,                   /* xEof */
      schemaColumn,                /* xColumn - read data */
      schemaRowid,                 /* xRowid - read data */
      null,                           /* xUpdate */
      null,                           /* xBegin */
      null,                           /* xSync */
      null,                           /* xCommit */
      null,                           /* xRollback */
      null,                           /* xFindMethod */
      null                            /* xRename */
      );

#endif //* !defined(SQLITE_OMIT_VIRTUALTABLE) */

#if SQLITE_TEST

    /*
** Decode a pointer to an sqlite3 object.
*/
    //extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);

    /*
    ** Register the schema virtual table module.
    */
    static int register_schema_module(
      ClientData clientData, /* Not used */
      Tcl_Interp interp,     /* The TCL interpreter that invoked this command */
      int objc,              /* Number of arguments */
      Tcl_Obj[] objv         /* Command arguments */
    )
    {
      sqlite3 db = null;
      if ( objc != 2 )
      {
        TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
        return TCL.TCL_ERROR;
      }
      if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
        return TCL.TCL_ERROR;
#if !SQLITE_OMIT_VIRTUALTABLE
      sqlite3_create_module( db, "schema", schemaModule, null );
#endif
      return TCL.TCL_OK;
    }

    /*
    ** Register commands with the TCL interpreter.
    */
    static public int Sqlitetestschema_Init( Tcl_Interp interp )
    {
      //static struct {
      //   char *zName;
      //   Tcl_ObjCmdProc *xProc;
      //   void *clientData;
      //} 
      _aObjCmd[] aObjCmd = new _aObjCmd[]{
     new _aObjCmd( "register_schema_module", register_schema_module, 0 ),
  };
      int i;
      for ( i = 0; i < aObjCmd.Length; i++ )//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
      {
        TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
            aObjCmd[i].xProc, aObjCmd[i].clientData, null );
      }
      return TCL.TCL_OK;
    }

#else

/*
** Extension load function.
*/
int sqlite3_extension_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
#if !SQLITE_OMIT_VIRTUALTABLE
  sqlite3_create_module(db, "schema", &schemaModule, 0);
#endif
  return 0;
}

#endif
  }
#endif
}