System.Data.SQLite

Check-in [accc5da1ee]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Sync up (fallback) error messages with those in the SQLite core library. Mask off extended error codes prior to using the fallback table. Add tests for preserving extended error codes in the SQLiteException class.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: accc5da1ee5c6e07a0472a35c7b5c4c8ecef6b5a
User & Date: mistachkin 2018-02-08 01:02:25.707
Context
2018-02-08
01:47
Update SQLite core library to the latest trunk code. check-in: d5bde3713d user: mistachkin tags: trunk
01:02
Sync up (fallback) error messages with those in the SQLite core library. Mask off extended error codes prior to using the fallback table. Add tests for preserving extended error codes in the SQLiteException class. check-in: accc5da1ee user: mistachkin tags: trunk
00:50
Override the System.Object members for the SQLiteException class to improve its ToString return value. Pursuant to [53962f9eff]. check-in: 37dcaf8f5d user: mistachkin tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to System.Data.SQLite/SQLiteBase.cs.
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635










636
637
638
639
640
641
642
643
644
645
646
    // a SQLiteStatementHandle, SQLiteConnectionHandle, and SQLiteFunctionCookieHandle.
    // Therefore these functions have to be static, and have to be low-level.

    ///////////////////////////////////////////////////////////////////////////////////////////////

    private static string[] _errorMessages = {
        /* SQLITE_OK          */ "not an error",
        /* SQLITE_ERROR       */ "SQL logic error or missing database",
        /* SQLITE_INTERNAL    */ "internal logic error",
        /* SQLITE_PERM        */ "access permission denied",
        /* SQLITE_ABORT       */ "callback requested query abort",
        /* SQLITE_BUSY        */ "database is locked",
        /* SQLITE_LOCKED      */ "database table is locked",
        /* SQLITE_NOMEM       */ "out of memory",
        /* SQLITE_READONLY    */ "attempt to write a readonly database",
        /* SQLITE_INTERRUPT   */ "interrupted",
        /* SQLITE_IOERR       */ "disk I/O error",
        /* SQLITE_CORRUPT     */ "database disk image is malformed",
        /* SQLITE_NOTFOUND    */ "unknown operation",
        /* SQLITE_FULL        */ "database or disk is full",
        /* SQLITE_CANTOPEN    */ "unable to open database file",
        /* SQLITE_PROTOCOL    */ "locking protocol",
        /* SQLITE_EMPTY       */ "table contains no data",
        /* SQLITE_SCHEMA      */ "database schema has changed",
        /* SQLITE_TOOBIG      */ "string or blob too big",
        /* SQLITE_CONSTRAINT  */ "constraint failed",
        /* SQLITE_MISMATCH    */ "datatype mismatch",
        /* SQLITE_MISUSE      */ "library routine called out of sequence",
        /* SQLITE_NOLFS       */ "large file support is disabled",
        /* SQLITE_AUTH        */ "authorization denied",
        /* SQLITE_FORMAT      */ "auxiliary database format error",
        /* SQLITE_RANGE       */ "bind or column index out of range",
        /* SQLITE_NOTADB      */ "file is encrypted or is not a database",
        /* SQLITE_NOTICE      */ "notification message",
        /* SQLITE_WARNING     */ "warning message"
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Returns the error message for the specified SQLite return code using
    /// the internal static lookup table.
    /// </summary>
    /// <param name="rc">The SQLite return code.</param>
    /// <returns>The error message or null if it cannot be found.</returns>
    protected static string FallbackGetErrorString(SQLiteErrorCode rc)
    {










        if (_errorMessages == null)
            return null;

        int index = (int)rc;

        if ((index < 0) || (index >= _errorMessages.Length))
            index = (int)SQLiteErrorCode.Error; /* Make into generic error. */

        return _errorMessages[index];
    }








|


|
















|



|
|














>
>
>
>
>
>
>
>
>
>



|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
    // a SQLiteStatementHandle, SQLiteConnectionHandle, and SQLiteFunctionCookieHandle.
    // Therefore these functions have to be static, and have to be low-level.

    ///////////////////////////////////////////////////////////////////////////////////////////////

    private static string[] _errorMessages = {
        /* SQLITE_OK          */ "not an error",
        /* SQLITE_ERROR       */ "SQL logic error",
        /* SQLITE_INTERNAL    */ "internal logic error",
        /* SQLITE_PERM        */ "access permission denied",
        /* SQLITE_ABORT       */ "query aborted",
        /* SQLITE_BUSY        */ "database is locked",
        /* SQLITE_LOCKED      */ "database table is locked",
        /* SQLITE_NOMEM       */ "out of memory",
        /* SQLITE_READONLY    */ "attempt to write a readonly database",
        /* SQLITE_INTERRUPT   */ "interrupted",
        /* SQLITE_IOERR       */ "disk I/O error",
        /* SQLITE_CORRUPT     */ "database disk image is malformed",
        /* SQLITE_NOTFOUND    */ "unknown operation",
        /* SQLITE_FULL        */ "database or disk is full",
        /* SQLITE_CANTOPEN    */ "unable to open database file",
        /* SQLITE_PROTOCOL    */ "locking protocol",
        /* SQLITE_EMPTY       */ "table contains no data",
        /* SQLITE_SCHEMA      */ "database schema has changed",
        /* SQLITE_TOOBIG      */ "string or blob too big",
        /* SQLITE_CONSTRAINT  */ "constraint failed",
        /* SQLITE_MISMATCH    */ "datatype mismatch",
        /* SQLITE_MISUSE      */ "bad parameter or other API misuse",
        /* SQLITE_NOLFS       */ "large file support is disabled",
        /* SQLITE_AUTH        */ "authorization denied",
        /* SQLITE_FORMAT      */ "auxiliary database format error",
        /* SQLITE_RANGE       */ "column index out of range",
        /* SQLITE_NOTADB      */ "file is not a database",
        /* SQLITE_NOTICE      */ "notification message",
        /* SQLITE_WARNING     */ "warning message"
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Returns the error message for the specified SQLite return code using
    /// the internal static lookup table.
    /// </summary>
    /// <param name="rc">The SQLite return code.</param>
    /// <returns>The error message or null if it cannot be found.</returns>
    protected static string FallbackGetErrorString(SQLiteErrorCode rc)
    {
        switch (rc)
        {
            case SQLiteErrorCode.Abort_Rollback:
                return "abort due to ROLLBACK";
            case SQLiteErrorCode.Row:
                return "another row available";
            case SQLiteErrorCode.Done:
                return "no more rows available";
        }

        if (_errorMessages == null)
            return null;

        int index = (int)(rc & SQLiteErrorCode.NonExtendedMask);

        if ((index < 0) || (index >= _errorMessages.Length))
            index = (int)SQLiteErrorCode.Error; /* Make into generic error. */

        return _errorMessages[index];
    }

Changes to Tests/basic.eagle.
4753
4754
4755
4756
4757
4758
4759

























































































4760
4761
4762
4763
4764
4765
4766

  unset -nocomplain msg db fileName
} -constraints [fixConstraints {eagle !System.Data.SQLite.Encryption monoBug28\
command.sql compile.DATA SQLite System.Data.SQLite}] -result {1 {SQL logic\
error -- Cannot use "HexPassword" connection string property: library was not\
built with encryption support, please see "https://www.sqlite.org/see" for more\
information}}}


























































































###############################################################################

reportSQLiteResources $test_channel

###############################################################################








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855

  unset -nocomplain msg db fileName
} -constraints [fixConstraints {eagle !System.Data.SQLite.Encryption monoBug28\
command.sql compile.DATA SQLite System.Data.SQLite}] -result {1 {SQL logic\
error -- Cannot use "HexPassword" connection string property: library was not\
built with encryption support, please see "https://www.sqlite.org/see" for more\
information}}}

###############################################################################

runTest {test data-1.93 {extended error code messages} -setup {
  #
  # HACK: Temporarily disable automatic detection (and use) of the
  #       native sqlite3_errstr() API.
  #
  object invoke -flags +NonPublic \
      System.Data.SQLite.SQLite3 have_errstr false

  setupDb [set fileName data-1.93.db]
} -body {
  set errCodes [list]

  lappend errCodes 256; # SQLITE_OK_LOAD_PERMANENTLY
  lappend errCodes 513; # SQLITE_ERROR_RETRY
  lappend errCodes 522; # SQLITE_IOERR_SHORT_READ
  lappend errCodes 270; # SQLITE_CANTOPEN_NOTEMPDIR
  lappend errCodes 539; # SQLITE_NOTICE_RECOVER_ROLLBACK
  lappend errCodes 284; # SQLITE_WARNING_AUTOINDEX

  set connection [getDbConnection]

  lappend result [catchAndReturn {$connection EnableExtensions true}]

  lappend result [catchAndReturn {$connection LoadExtension \
      [getCoreExtensionBinaryFileName null] interop_test_extension_init}]

  lappend result [catchAndReturn {$connection SetExtendedResultCodes false}]

  foreach errCode $errCodes {
    #
    # HACK: Without extended error codes, SQLITE_OK_* cannot be handled via
    #       the semantics in the System.Data.SQLite.SQLite3.Prepare method;
    #       it will always assume that more results are available when the
    #       error code is Ok, thereby looping forever.
    #
    if {($errCode & 0xFF) == 0} then {continue}

    resetException; catchAndSetException {
      sql execute -execute scalar $db \
          "SELECT interopError(?);" [list param1 Int32 $errCode]
    } exception

    lappend result [$exception ResultCode] \
        [normalizeExceptionMessage [$exception Message]]
  }

  lappend result [catchAndReturn {$connection SetExtendedResultCodes true}]

  foreach errCode $errCodes {
    resetException; catchAndSetException {
      sql execute -execute scalar $db \
          "SELECT interopError(?);" [list param1 Int32 $errCode]
    } exception

    lappend result [$exception ResultCode] \
        [normalizeExceptionMessage [$exception Message]]
  }

  set result
} -cleanup {
  cleanupDb $fileName

  freeDbConnection

  catch {
    #
    # HACK: Restore automatic detection (and use) of the native
    #       sqlite3_errstr() API.
    #
    object invoke -flags +NonPublic \
        System.Data.SQLite.SQLite3 have_errstr null
  }

  unset -nocomplain result exception errCode errCodes
  unset -nocomplain connection db fileName
} -constraints {eagle command.object monoBug28\
compile.DATA defineConstant.System.Data.SQLite.INTEROP_TEST_EXTENSION\
command.sql SQLite System.Data.SQLite} -result {{0 {}} {0 {}} {0 {}} Error {SQL\
logic error ==> SQL logic error} IoErr {disk I/O error ==> disk I/O error}\
CantOpen {unable to open database file ==> unable to open database file} Notice\
{notification message ==> unknown error} Warning {warning message ==> unknown\
error} {0 {}} Ok_Load_Permanently {not an error ==> not an error} Error_Retry\
{SQL logic error ==> SQL logic error} IoErr_Short_Read {disk I/O error ==> disk\
I/O error} CantOpen_NoTempDir {unable to open database file ==> unable to open\
database file} Notice_Recover_Rollback {notification message ==> unknown error}\
Warning_AutoIndex {warning message ==> unknown error}}}

###############################################################################

reportSQLiteResources $test_channel

###############################################################################

Changes to lib/System.Data.SQLite/common.eagle.
2167
2168
2169
2170
2171
2172
2173






























2174
2175
2176
2177
2178
2179
2180
        #       code for the interpreter, and the error message up to the
        #       point where the stack trace should start.
        #
        return [list $code $::errorCode \
            [extractSystemDataSQLiteExceptionMessage $result]]
      }
    }































    proc compileCSharpWith {
            text memory symbols strict resultsVarName errorsVarName fileNames
            args } {
      #
      # NOTE: Since we are going to use this method name a lot, assign it to a
      #       variable first.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
        #       code for the interpreter, and the error message up to the
        #       point where the stack trace should start.
        #
        return [list $code $::errorCode \
            [extractSystemDataSQLiteExceptionMessage $result]]
      }
    }

    proc resetException {} {
      #
      # NOTE: Reset exception associated with this interpreter (to null).
      #       This (private) property is maintained on a per-thread basis.
      #
      object invoke -flags +NonPublic Interpreter.GetActive Exception null
      return ""
    }

    proc catchAndSetException { script {varName ""} } {
      #
      # NOTE: Evaluate the script provided by our caller in their context.
      #
      catch {uplevel 1 $script}

      #
      # NOTE: Grab the (private) exception property from this interpreter,
      #       for this thread, and add as an opaque object handle in the
      #       context of our caller.
      #
      if {[string length $varName] > 0} then {
        upvar 1 $varName exception
      }

      set exception [object invoke \
          -alias -flags +NonPublic Interpreter.GetActive Exception]

      return ""
    }

    proc compileCSharpWith {
            text memory symbols strict resultsVarName errorsVarName fileNames
            args } {
      #
      # NOTE: Since we are going to use this method name a lot, assign it to a
      #       variable first.
2284
2285
2286
2287
2288
2289
2290





2291
2292
2293
2294
2295
2296
2297
        PRAGMA cache_size = 2000;
      }

      return [list \
          [sql execute -execute scalar $db "PRAGMA page_size;"] \
          [sql execute -execute scalar $db "PRAGMA cache_size;"]]
    }






    proc extractSystemDataSQLiteExceptionMessage { value } {
      #
      # NOTE: If the string conforms to format of the normal exception
      #       error strings, extract and return only the error message
      #       portion itself.
      #







>
>
>
>
>







2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
        PRAGMA cache_size = 2000;
      }

      return [list \
          [sql execute -execute scalar $db "PRAGMA page_size;"] \
          [sql execute -execute scalar $db "PRAGMA cache_size;"]]
    }

    proc normalizeExceptionMessage { value } {
      if {[string length $value] == 0} then {return $value}
      return [string map [list \r\n " ==> "] $value]
    }

    proc extractSystemDataSQLiteExceptionMessage { value } {
      #
      # NOTE: If the string conforms to format of the normal exception
      #       error strings, extract and return only the error message
      #       portion itself.
      #