System.Data.SQLite
Check-in [c956230a3c]
Not logged in

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

Overview
Comment:Prevent GetSchemaTable from throwing InvalidCastException. Fix for [baf42ee135].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c956230a3c38797797cb1343296ce57c1ab256e8
User & Date: mistachkin 2018-03-08 18:13:24
References
2018-05-29
01:04 Ticket [baf42ee135] Unable to cast object of type 'System.DBNull' to type 'System.String' status still Closed with 3 other changes artifact: 518e16e143 user: mistachkin
Context
2018-03-08
20:50
Internal enhancements to the native memory allocation wrapper. check-in: fcac33cc7a user: mistachkin tags: trunk
18:13
Prevent GetSchemaTable from throwing InvalidCastException. Fix for [baf42ee135]. check-in: c956230a3c user: mistachkin tags: trunk
18:11
Update SQLite core library to the latest trunk code. check-in: 5548dace23 user: mistachkin tags: trunk
16:23
Some further related cleanup in the GetSchemaTable method. Closed-Leaf check-in: 36be86807a user: mistachkin tags: tkt-baf42ee135
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to Setup/data/verify.lst.

895
896
897
898
899
900
901

902
903
904
905
906
907
908
  Tests/tkt-a799e3978f.eagle
  Tests/tkt-a7d04fb111.eagle
  Tests/tkt-aba4549801.eagle
  Tests/tkt-ac47dd230a.eagle
  Tests/tkt-ae5267b863.eagle
  Tests/tkt-b167206ad3.eagle
  Tests/tkt-b4a7ddc83f.eagle

  Tests/tkt-bb4b04d457.eagle
  Tests/tkt-c010fa6584.eagle
  Tests/tkt-c28d7fe915.eagle
  Tests/tkt-ccfa69fc32.eagle
  Tests/tkt-d4728aecb7.eagle
  Tests/tkt-da685c0bac.eagle
  Tests/tkt-da9f18d039.eagle







>







895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
  Tests/tkt-a799e3978f.eagle
  Tests/tkt-a7d04fb111.eagle
  Tests/tkt-aba4549801.eagle
  Tests/tkt-ac47dd230a.eagle
  Tests/tkt-ae5267b863.eagle
  Tests/tkt-b167206ad3.eagle
  Tests/tkt-b4a7ddc83f.eagle
  Tests/tkt-baf42ee135.eagle
  Tests/tkt-bb4b04d457.eagle
  Tests/tkt-c010fa6584.eagle
  Tests/tkt-c28d7fe915.eagle
  Tests/tkt-ccfa69fc32.eagle
  Tests/tkt-d4728aecb7.eagle
  Tests/tkt-da685c0bac.eagle
  Tests/tkt-da9f18d039.eagle

Changes to System.Data.SQLite/SQLiteDataReader.cs.

1481
1482
1483
1484
1485
1486
1487















1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501

1502
1503
1504
1505
1506
1507
1508
....
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
        temp = columnToParent[n].DatabaseName;
        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;

        string dataType = null;
        // If we have a table-bound column, extract the extra information from it
        if (String.IsNullOrEmpty(strColumn) == false)
        {















          string collSeq = null;
          bool bNotNull = false;
          bool bPrimaryKey = false;
          bool bAutoIncrement = false;
          string[] arSize;

          // Get the column meta data
          _command.Connection._sql.ColumnMetaData(
            (string)row[SchemaTableOptionalColumn.BaseCatalogName],
            (string)row[SchemaTableColumn.BaseTableName],
            strColumn,
            ref dataType, ref collSeq, ref bNotNull, ref bPrimaryKey, ref bAutoIncrement);

          if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;


          row[SchemaTableColumn.IsKey] = bPrimaryKey && CountParents(parentToColumns) <= 1;
          row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
          row["CollationType"] = collSeq;

          // For types like varchar(50) and such, extract the size
          arSize = dataType.Split('(');
................................................................................
            }
          }

          if (wantDefaultValue)
          {
            // Determine the default value for the column, which sucks because we have to query the schema for each column
            using (SQLiteCommand cmdTable = new SQLiteCommand(HelperMethods.StringFormat(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
              row[SchemaTableOptionalColumn.BaseCatalogName],
              row[SchemaTableColumn.BaseTableName]
              ), _command.Connection))
            using (DbDataReader rdTable = cmdTable.ExecuteReader())
            {
              // Find the matching column
              while (rdTable.Read())
              {
                if (String.Compare((string)row[SchemaTableColumn.BaseColumnName], rdTable.GetString(1), StringComparison.OrdinalIgnoreCase) == 0)
                {
                  if (rdTable.IsDBNull(4) == false)
                    row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];

                  break;
                }
              }
            }
          }

          // Determine IsUnique properly, which is a pain in the butt!
          if (wantUniqueInfo)
          {
            if ((string)row[SchemaTableOptionalColumn.BaseCatalogName] != strCatalog
              || (string)row[SchemaTableColumn.BaseTableName] != strTable)
            {
              strCatalog = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
              strTable = (string)row[SchemaTableColumn.BaseTableName];

              tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
                null,
                (string)row[SchemaTableColumn.BaseTableName],
                null });
            }

            foreach (DataRow rowIndexes in tblIndexes.Rows)
            {
              tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
                null,
                (string)row[SchemaTableColumn.BaseTableName],
                (string)rowIndexes["INDEX_NAME"],
                null
                });
              foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
              {
                if (String.Compare(SQLiteConvert.GetStringOrNull(rowColumnIndex["COLUMN_NAME"]), strColumn, StringComparison.OrdinalIgnoreCase) == 0)
                {
                  //
                  // BUGFIX: Make sure that we only flag this column as "unique"
                  //         if we are not processing of some kind of multi-table
                  //         construct (i.e. a join) because in that case we must
                  //         allow duplicate values (refer to ticket [7e3fa93744]).
                  //
                  if (parentToColumns.Count == 1 && tblIndexColumns.Rows.Count == 1 && (bool)row[SchemaTableColumn.AllowDBNull] == false)
                    row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];

                  // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
                  // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
                  //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
                  //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.








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








|
|




>







 







|
|






|













|
|

|
|


|

|






|

|













|







1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
....
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
        temp = columnToParent[n].DatabaseName;
        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;

        string dataType = null;
        // If we have a table-bound column, extract the extra information from it
        if (String.IsNullOrEmpty(strColumn) == false)
        {
          string baseCatalogName = String.Empty;

          if (row[SchemaTableOptionalColumn.BaseCatalogName] != DBNull.Value)
              baseCatalogName = (string)row[SchemaTableOptionalColumn.BaseCatalogName];

          string baseTableName = String.Empty;

          if (row[SchemaTableColumn.BaseTableName] != DBNull.Value)
              baseTableName = (string)row[SchemaTableColumn.BaseTableName];

          string baseColumnName = String.Empty;

          if (row[SchemaTableColumn.BaseColumnName] != DBNull.Value)
              baseColumnName = (string)row[SchemaTableColumn.BaseColumnName];

          string collSeq = null;
          bool bNotNull = false;
          bool bPrimaryKey = false;
          bool bAutoIncrement = false;
          string[] arSize;

          // Get the column meta data
          _command.Connection._sql.ColumnMetaData(
            baseCatalogName,
            baseTableName,
            strColumn,
            ref dataType, ref collSeq, ref bNotNull, ref bPrimaryKey, ref bAutoIncrement);

          if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
          bool allowDbNull = (bool)row[SchemaTableColumn.AllowDBNull];

          row[SchemaTableColumn.IsKey] = bPrimaryKey && CountParents(parentToColumns) <= 1;
          row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
          row["CollationType"] = collSeq;

          // For types like varchar(50) and such, extract the size
          arSize = dataType.Split('(');
................................................................................
            }
          }

          if (wantDefaultValue)
          {
            // Determine the default value for the column, which sucks because we have to query the schema for each column
            using (SQLiteCommand cmdTable = new SQLiteCommand(HelperMethods.StringFormat(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
              baseCatalogName,
              baseTableName
              ), _command.Connection))
            using (DbDataReader rdTable = cmdTable.ExecuteReader())
            {
              // Find the matching column
              while (rdTable.Read())
              {
                if (String.Compare(baseColumnName, rdTable.GetString(1), StringComparison.OrdinalIgnoreCase) == 0)
                {
                  if (rdTable.IsDBNull(4) == false)
                    row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];

                  break;
                }
              }
            }
          }

          // Determine IsUnique properly, which is a pain in the butt!
          if (wantUniqueInfo)
          {
            if (baseCatalogName != strCatalog
              || baseTableName != strTable)
            {
              strCatalog = baseCatalogName;
              strTable = baseTableName;

              tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
                baseCatalogName,
                null,
                baseTableName,
                null });
            }

            foreach (DataRow rowIndexes in tblIndexes.Rows)
            {
              tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
                baseCatalogName,
                null,
                baseTableName,
                (string)rowIndexes["INDEX_NAME"],
                null
                });
              foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
              {
                if (String.Compare(SQLiteConvert.GetStringOrNull(rowColumnIndex["COLUMN_NAME"]), strColumn, StringComparison.OrdinalIgnoreCase) == 0)
                {
                  //
                  // BUGFIX: Make sure that we only flag this column as "unique"
                  //         if we are not processing of some kind of multi-table
                  //         construct (i.e. a join) because in that case we must
                  //         allow duplicate values (refer to ticket [7e3fa93744]).
                  //
                  if (parentToColumns.Count == 1 && tblIndexColumns.Rows.Count == 1 && allowDbNull == false)
                    row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];

                  // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
                  // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
                  //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
                  //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.

Added Tests/tkt-baf42ee135.eagle.













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
###############################################################################
#
# tkt-baf42ee135.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

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

package require System.Data.SQLite.Test
runSQLiteTestPrologue

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

runTest {test tkt-baf42ee135-1.1 {base catalog/table name not set} -setup {
  setupDb [set fileName tkt-baf42ee135-1.1.db]
} -body {
  sql execute $db {
    CREATE TABLE ""(x);
  }

  set dataReader [sql execute -execute reader -format datareader \
      -alias $db "SELECT x FROM \"\";"]

  set dataTable [$dataReader -alias GetSchemaTable]

  getRowsFromDataTable $dataTable
} -cleanup {
  unset -nocomplain dataTable dataReader

  cleanupDb $fileName

  unset -nocomplain db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{{ColumnName x} {ColumnOrdinal 0} {ColumnSize\
2147483647} NumericPrecision NumericScale {IsUnique False} {IsKey False}\
BaseServerName {BaseCatalogName main} {BaseColumnName x} {BaseSchemaName\
sqlite_default_schema} BaseTableName {DataType System.Object} {AllowDBNull\
True} {ProviderType 13} {IsAliased False} {IsExpression False} {IsAutoIncrement\
False} {IsRowVersion False} {IsHidden False} {IsLong False} {IsReadOnly False}\
ProviderSpecificDataType DefaultValue DataTypeName {CollationType BINARY}}}}

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

runSQLiteTestEpilogue
runTestEpilogue