System.Data.SQLite
Check-in [63ae5401bf]
Not logged in

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

Overview
Comment:The GetSchemaTable method must verify the base table name (for a column) actually refers to a base table before attempting to query its metadata. Pursuant to [baf42ee135].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 63ae5401bfd3fbba2468b9f7cdaf862537987640
User & Date: mistachkin 2018-03-09 17:45:03
Context
2018-03-09
21:47
Fix typos in the data reader class that could lead to them returning the wrong value for GetDatabaseName / GetTableName methods. check-in: 785601b768 user: mistachkin tags: trunk
17:45
The GetSchemaTable method must verify the base table name (for a column) actually refers to a base table before attempting to query its metadata. Pursuant to [baf42ee135]. check-in: 63ae5401bf user: mistachkin tags: trunk
17:41
Further improvements to the catalog name and master table name handling in the connection class. check-in: 9bb5fe6f96 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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

  2071   2071         int len = 0;
  2072   2072         return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name_interop(stmt._sqlite_stmt, index, ref len), len);
  2073   2073   #else
  2074   2074         return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name(stmt._sqlite_stmt, index), -1);
  2075   2075   #endif
  2076   2076       }
  2077   2077   
  2078         -    internal override void ColumnMetaData(string dataBase, string table, string column, ref string dataType, ref string collateSequence, ref bool notNull, ref bool primaryKey, ref bool autoIncrement)
         2078  +    internal override bool DoesTableExist(
         2079  +        string dataBase,
         2080  +        string table
         2081  +        )
         2082  +    {
         2083  +        string dataType = null; /* NOT USED */
         2084  +        string collateSequence = null; /* NOT USED */
         2085  +        bool notNull = false; /* NOT USED */
         2086  +        bool primaryKey = false; /* NOT USED */
         2087  +        bool autoIncrement = false; /* NOT USED */
         2088  +
         2089  +        return ColumnMetaData(
         2090  +            dataBase, table, null, false, ref dataType,
         2091  +            ref collateSequence, ref notNull, ref primaryKey,
         2092  +            ref autoIncrement);
         2093  +    }
         2094  +
         2095  +    internal override bool ColumnMetaData(string dataBase, string table, string column, bool canThrow, ref string dataType, ref string collateSequence, ref bool notNull, ref bool primaryKey, ref bool autoIncrement)
  2079   2096       {
  2080   2097         IntPtr dataTypePtr = IntPtr.Zero;
  2081   2098         IntPtr collSeqPtr = IntPtr.Zero;
  2082   2099         int nnotNull = 0;
  2083   2100         int nprimaryKey = 0;
  2084   2101         int nautoInc = 0;
  2085   2102         SQLiteErrorCode n;
................................................................................
  2092   2109         n = UnsafeNativeMethods.sqlite3_table_column_metadata_interop(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), ref dataTypePtr, ref collSeqPtr, ref nnotNull, ref nprimaryKey, ref nautoInc, ref dtLen, ref csLen);
  2093   2110   #else
  2094   2111         dtLen = -1;
  2095   2112         csLen = -1;
  2096   2113   
  2097   2114         n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), ref dataTypePtr, ref collSeqPtr, ref nnotNull, ref nprimaryKey, ref nautoInc);
  2098   2115   #endif
  2099         -      if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
         2116  +      if (canThrow && (n != SQLiteErrorCode.Ok)) throw new SQLiteException(n, GetLastError());
  2100   2117   
  2101   2118         dataType = UTF8ToString(dataTypePtr, dtLen);
  2102   2119         collateSequence = UTF8ToString(collSeqPtr, csLen);
  2103   2120   
  2104   2121         notNull = (nnotNull == 1);
  2105   2122         primaryKey = (nprimaryKey == 1);
  2106   2123         autoIncrement = (nautoInc == 1);
         2124  +
         2125  +      return (n == SQLiteErrorCode.Ok);
  2107   2126       }
  2108   2127   
  2109   2128       internal override object GetObject(SQLiteStatement stmt, int index)
  2110   2129       {
  2111   2130           switch (ColumnAffinity(stmt, index))
  2112   2131           {
  2113   2132               case TypeAffinity.Int64:

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

   251    251       internal abstract string ColumnName(SQLiteStatement stmt, int index);
   252    252       internal abstract TypeAffinity ColumnAffinity(SQLiteStatement stmt, int index);
   253    253       internal abstract string ColumnType(SQLiteStatement stmt, int index, ref TypeAffinity nAffinity);
   254    254       internal abstract int ColumnIndex(SQLiteStatement stmt, string columnName);
   255    255       internal abstract string ColumnOriginalName(SQLiteStatement stmt, int index);
   256    256       internal abstract string ColumnDatabaseName(SQLiteStatement stmt, int index);
   257    257       internal abstract string ColumnTableName(SQLiteStatement stmt, int index);
   258         -    internal abstract void ColumnMetaData(string dataBase, string table, string column, ref string dataType, ref string collateSequence, ref bool notNull, ref bool primaryKey, ref bool autoIncrement);
          258  +    internal abstract bool DoesTableExist(string dataBase, string table);
          259  +    internal abstract bool ColumnMetaData(string dataBase, string table, string column, bool canThrow, ref string dataType, ref string collateSequence, ref bool notNull, ref bool primaryKey, ref bool autoIncrement);
   259    260       internal abstract void GetIndexColumnExtendedInfo(string database, string index, string column, ref int sortMode, ref int onError, ref string collationSequence);
   260    261   
   261    262       internal abstract object GetObject(SQLiteStatement stmt, int index);
   262    263       internal abstract double GetDouble(SQLiteStatement stmt, int index);
   263    264       internal abstract Boolean GetBoolean(SQLiteStatement stmt, int index);
   264    265       internal abstract SByte GetSByte(SQLiteStatement stmt, int index);
   265    266       internal abstract Byte GetByte(SQLiteStatement stmt, int index);

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

  1379   1379           return result;
  1380   1380       }
  1381   1381   
  1382   1382       ///////////////////////////////////////////////////////////////////////////
  1383   1383   
  1384   1384       internal DataTable GetSchemaTable(bool wantUniqueInfo, bool wantDefaultValue)
  1385   1385       {
  1386         -      CheckClosed();
  1387         -      if (_throwOnDisposed) SQLiteCommand.Check(_command);
  1388         -
  1389         -      //
  1390         -      // BUGFIX: We need to quickly scan all the fields in the current
  1391         -      //         "result set" to see how many distinct tables are actually
  1392         -      //         involved.  This information is necessary so that some
  1393         -      //         intelligent decisions can be made when constructing the
  1394         -      //         metadata below.  For example, we need to be very careful
  1395         -      //         about flagging a particular column as "unique" just
  1396         -      //         because it was in its original underlying database table
  1397         -      //         if there are now multiple tables involved in the
  1398         -      //         "result set".  See ticket [7e3fa93744] for more detailed
  1399         -      //         information.
  1400         -      //
  1401         -      Dictionary<ColumnParent, List<int>> parentToColumns = null;
  1402         -      Dictionary<int, ColumnParent> columnToParent = null;
  1403         -
  1404         -      GetStatementColumnParents(
  1405         -          _command.Connection._sql, _activeStatement, _fieldCount,
  1406         -          ref parentToColumns, ref columnToParent);
  1407         -
  1408         -      DataTable tbl = new DataTable("SchemaTable");
  1409         -      DataTable tblIndexes = null;
  1410         -      DataTable tblIndexColumns;
  1411         -      DataRow row;
  1412         -      string temp;
  1413         -      string strCatalog = String.Empty;
  1414         -      string strTable = String.Empty;
  1415         -      string strColumn = String.Empty;
  1416         -
  1417         -      tbl.Locale = CultureInfo.InvariantCulture;
  1418         -      tbl.Columns.Add(SchemaTableColumn.ColumnName, typeof(String));
  1419         -      tbl.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
  1420         -      tbl.Columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
  1421         -      tbl.Columns.Add(SchemaTableColumn.NumericPrecision, typeof(int));
  1422         -      tbl.Columns.Add(SchemaTableColumn.NumericScale, typeof(int));
  1423         -      tbl.Columns.Add(SchemaTableColumn.IsUnique, typeof(Boolean));
  1424         -      tbl.Columns.Add(SchemaTableColumn.IsKey, typeof(Boolean));
  1425         -      tbl.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
  1426         -      tbl.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(String));
  1427         -      tbl.Columns.Add(SchemaTableColumn.BaseColumnName, typeof(String));
  1428         -      tbl.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof(String));
  1429         -      tbl.Columns.Add(SchemaTableColumn.BaseTableName, typeof(String));
  1430         -      tbl.Columns.Add(SchemaTableColumn.DataType, typeof(Type));
  1431         -      tbl.Columns.Add(SchemaTableColumn.AllowDBNull, typeof(Boolean));
  1432         -      tbl.Columns.Add(SchemaTableColumn.ProviderType, typeof(int));
  1433         -      tbl.Columns.Add(SchemaTableColumn.IsAliased, typeof(Boolean));
  1434         -      tbl.Columns.Add(SchemaTableColumn.IsExpression, typeof(Boolean));
  1435         -      tbl.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(Boolean));
  1436         -      tbl.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(Boolean));
  1437         -      tbl.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(Boolean));
  1438         -      tbl.Columns.Add(SchemaTableColumn.IsLong, typeof(Boolean));
  1439         -      tbl.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(Boolean));
  1440         -      tbl.Columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
  1441         -      tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof(object));
  1442         -      tbl.Columns.Add("DataTypeName", typeof(string));
  1443         -      tbl.Columns.Add("CollationType", typeof(string));
  1444         -      tbl.BeginLoadData();
  1445         -
  1446         -      for (int n = 0; n < _fieldCount; n++)
  1447         -      {
  1448         -        SQLiteType sqlType = GetSQLiteType(_flags, n);
  1449         -
  1450         -        row = tbl.NewRow();
  1451         -
  1452         -        DbType typ = sqlType.Type;
  1453         -
  1454         -        // Default settings for the column
  1455         -        row[SchemaTableColumn.ColumnName] = GetName(n);
  1456         -        row[SchemaTableColumn.ColumnOrdinal] = n;
  1457         -        row[SchemaTableColumn.ColumnSize] = SQLiteConvert.DbTypeToColumnSize(typ);
  1458         -        row[SchemaTableColumn.NumericPrecision] = SQLiteConvert.DbTypeToNumericPrecision(typ);
  1459         -        row[SchemaTableColumn.NumericScale] = SQLiteConvert.DbTypeToNumericScale(typ);
  1460         -        row[SchemaTableColumn.ProviderType] = sqlType.Type;
  1461         -        row[SchemaTableColumn.IsLong] = false;
  1462         -        row[SchemaTableColumn.AllowDBNull] = true;
  1463         -        row[SchemaTableOptionalColumn.IsReadOnly] = false;
  1464         -        row[SchemaTableOptionalColumn.IsRowVersion] = false;
  1465         -        row[SchemaTableColumn.IsUnique] = false;
  1466         -        row[SchemaTableColumn.IsKey] = false;
  1467         -        row[SchemaTableOptionalColumn.IsAutoIncrement] = false;
  1468         -        row[SchemaTableColumn.DataType] = GetFieldType(n);
  1469         -        row[SchemaTableOptionalColumn.IsHidden] = false;
  1470         -        row[SchemaTableColumn.BaseSchemaName] = _baseSchemaName;
  1471         -
  1472         -        strColumn = columnToParent[n].ColumnName;
  1473         -        if (String.IsNullOrEmpty(strColumn) == false) row[SchemaTableColumn.BaseColumnName] = strColumn;
  1474         -
  1475         -        row[SchemaTableColumn.IsExpression] = String.IsNullOrEmpty(strColumn);
  1476         -        row[SchemaTableColumn.IsAliased] = (String.Compare(GetName(n), strColumn, StringComparison.OrdinalIgnoreCase) != 0);
  1477         -
  1478         -        temp = columnToParent[n].TableName;
  1479         -        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableColumn.BaseTableName] = temp;
  1480         -
  1481         -        temp = columnToParent[n].DatabaseName;
  1482         -        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;
  1483         -
  1484         -        string dataType = null;
  1485         -        // If we have a table-bound column, extract the extra information from it
  1486         -        if (String.IsNullOrEmpty(strColumn) == false)
  1487         -        {
  1488         -          string baseCatalogName = String.Empty;
  1489         -
  1490         -          if (row[SchemaTableOptionalColumn.BaseCatalogName] != DBNull.Value)
  1491         -              baseCatalogName = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
  1492         -
  1493         -          string baseTableName = String.Empty;
  1494         -
  1495         -          if (row[SchemaTableColumn.BaseTableName] != DBNull.Value)
  1496         -              baseTableName = (string)row[SchemaTableColumn.BaseTableName];
  1497         -
  1498         -          string baseColumnName = String.Empty;
  1499         -
  1500         -          if (row[SchemaTableColumn.BaseColumnName] != DBNull.Value)
  1501         -              baseColumnName = (string)row[SchemaTableColumn.BaseColumnName];
  1502         -
  1503         -          string collSeq = null;
  1504         -          bool bNotNull = false;
  1505         -          bool bPrimaryKey = false;
  1506         -          bool bAutoIncrement = false;
  1507         -          string[] arSize;
  1508         -
  1509         -          // Get the column meta data
  1510         -          _command.Connection._sql.ColumnMetaData(
  1511         -            baseCatalogName,
  1512         -            baseTableName,
  1513         -            strColumn,
  1514         -            ref dataType, ref collSeq, ref bNotNull, ref bPrimaryKey, ref bAutoIncrement);
  1515         -
  1516         -          if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
  1517         -          bool allowDbNull = (bool)row[SchemaTableColumn.AllowDBNull];
  1518         -
  1519         -          row[SchemaTableColumn.IsKey] = bPrimaryKey && CountParents(parentToColumns) <= 1;
  1520         -          row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
  1521         -          row["CollationType"] = collSeq;
  1522         -
  1523         -          // For types like varchar(50) and such, extract the size
  1524         -          arSize = dataType.Split('(');
  1525         -          if (arSize.Length > 1)
  1526         -          {
  1527         -            dataType = arSize[0];
  1528         -            arSize = arSize[1].Split(')');
  1529         -            if (arSize.Length > 1)
         1386  +        CheckClosed();
         1387  +        if (_throwOnDisposed) SQLiteCommand.Check(_command);
         1388  +
         1389  +        //
         1390  +        // BUGFIX: We need to quickly scan all the fields in the current
         1391  +        //         "result set" to see how many distinct tables are actually
         1392  +        //         involved.  This information is necessary so that some
         1393  +        //         intelligent decisions can be made when constructing the
         1394  +        //         metadata below.  For example, we need to be very careful
         1395  +        //         about flagging a particular column as "unique" just
         1396  +        //         because it was in its original underlying database table
         1397  +        //         if there are now multiple tables involved in the
         1398  +        //         "result set".  See ticket [7e3fa93744] for more detailed
         1399  +        //         information.
         1400  +        //
         1401  +        Dictionary<ColumnParent, List<int>> parentToColumns = null;
         1402  +        Dictionary<int, ColumnParent> columnToParent = null;
         1403  +        SQLiteBase sql = _command.Connection._sql;
         1404  +
         1405  +        GetStatementColumnParents(
         1406  +            sql, _activeStatement, _fieldCount,
         1407  +            ref parentToColumns, ref columnToParent);
         1408  +
         1409  +        DataTable tbl = new DataTable("SchemaTable");
         1410  +        DataTable tblIndexes = null;
         1411  +        DataTable tblIndexColumns;
         1412  +        DataRow row;
         1413  +        string temp;
         1414  +        string strCatalog = String.Empty;
         1415  +        string strTable = String.Empty;
         1416  +        string strColumn = String.Empty;
         1417  +
         1418  +        tbl.Locale = CultureInfo.InvariantCulture;
         1419  +        tbl.Columns.Add(SchemaTableColumn.ColumnName, typeof(String));
         1420  +        tbl.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
         1421  +        tbl.Columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
         1422  +        tbl.Columns.Add(SchemaTableColumn.NumericPrecision, typeof(int));
         1423  +        tbl.Columns.Add(SchemaTableColumn.NumericScale, typeof(int));
         1424  +        tbl.Columns.Add(SchemaTableColumn.IsUnique, typeof(Boolean));
         1425  +        tbl.Columns.Add(SchemaTableColumn.IsKey, typeof(Boolean));
         1426  +        tbl.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
         1427  +        tbl.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(String));
         1428  +        tbl.Columns.Add(SchemaTableColumn.BaseColumnName, typeof(String));
         1429  +        tbl.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof(String));
         1430  +        tbl.Columns.Add(SchemaTableColumn.BaseTableName, typeof(String));
         1431  +        tbl.Columns.Add(SchemaTableColumn.DataType, typeof(Type));
         1432  +        tbl.Columns.Add(SchemaTableColumn.AllowDBNull, typeof(Boolean));
         1433  +        tbl.Columns.Add(SchemaTableColumn.ProviderType, typeof(int));
         1434  +        tbl.Columns.Add(SchemaTableColumn.IsAliased, typeof(Boolean));
         1435  +        tbl.Columns.Add(SchemaTableColumn.IsExpression, typeof(Boolean));
         1436  +        tbl.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(Boolean));
         1437  +        tbl.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(Boolean));
         1438  +        tbl.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(Boolean));
         1439  +        tbl.Columns.Add(SchemaTableColumn.IsLong, typeof(Boolean));
         1440  +        tbl.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(Boolean));
         1441  +        tbl.Columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
         1442  +        tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof(object));
         1443  +        tbl.Columns.Add("DataTypeName", typeof(string));
         1444  +        tbl.Columns.Add("CollationType", typeof(string));
         1445  +        tbl.BeginLoadData();
         1446  +
         1447  +        for (int n = 0; n < _fieldCount; n++)
         1448  +        {
         1449  +            SQLiteType sqlType = GetSQLiteType(_flags, n);
         1450  +
         1451  +            row = tbl.NewRow();
         1452  +
         1453  +            DbType typ = sqlType.Type;
         1454  +
         1455  +            // Default settings for the column
         1456  +            row[SchemaTableColumn.ColumnName] = GetName(n);
         1457  +            row[SchemaTableColumn.ColumnOrdinal] = n;
         1458  +            row[SchemaTableColumn.ColumnSize] = SQLiteConvert.DbTypeToColumnSize(typ);
         1459  +            row[SchemaTableColumn.NumericPrecision] = SQLiteConvert.DbTypeToNumericPrecision(typ);
         1460  +            row[SchemaTableColumn.NumericScale] = SQLiteConvert.DbTypeToNumericScale(typ);
         1461  +            row[SchemaTableColumn.ProviderType] = sqlType.Type;
         1462  +            row[SchemaTableColumn.IsLong] = false;
         1463  +            row[SchemaTableColumn.AllowDBNull] = true;
         1464  +            row[SchemaTableOptionalColumn.IsReadOnly] = false;
         1465  +            row[SchemaTableOptionalColumn.IsRowVersion] = false;
         1466  +            row[SchemaTableColumn.IsUnique] = false;
         1467  +            row[SchemaTableColumn.IsKey] = false;
         1468  +            row[SchemaTableOptionalColumn.IsAutoIncrement] = false;
         1469  +            row[SchemaTableColumn.DataType] = GetFieldType(n);
         1470  +            row[SchemaTableOptionalColumn.IsHidden] = false;
         1471  +            row[SchemaTableColumn.BaseSchemaName] = _baseSchemaName;
         1472  +
         1473  +            strColumn = columnToParent[n].ColumnName;
         1474  +            if (String.IsNullOrEmpty(strColumn) == false) row[SchemaTableColumn.BaseColumnName] = strColumn;
         1475  +
         1476  +            row[SchemaTableColumn.IsExpression] = String.IsNullOrEmpty(strColumn);
         1477  +            row[SchemaTableColumn.IsAliased] = (String.Compare(GetName(n), strColumn, StringComparison.OrdinalIgnoreCase) != 0);
         1478  +
         1479  +            temp = columnToParent[n].TableName;
         1480  +            if (String.IsNullOrEmpty(temp) == false) row[SchemaTableColumn.BaseTableName] = temp;
         1481  +
         1482  +            temp = columnToParent[n].DatabaseName;
         1483  +            if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;
         1484  +
         1485  +            string dataType = null;
         1486  +            // If we have a table-bound column, extract the extra information from it
         1487  +            if (String.IsNullOrEmpty(strColumn) == false)
  1530   1488               {
  1531         -              arSize = arSize[0].Split(',', '.');
  1532         -              if (sqlType.Type == DbType.Binary || SQLiteConvert.IsStringDbType(sqlType.Type))
  1533         -              {
  1534         -                row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
  1535         -              }
  1536         -              else
  1537         -              {
  1538         -                row[SchemaTableColumn.NumericPrecision] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
  1539         -                if (arSize.Length > 1)
  1540         -                  row[SchemaTableColumn.NumericScale] = Convert.ToInt32(arSize[1], CultureInfo.InvariantCulture);
  1541         -              }
  1542         -            }
  1543         -          }
  1544         -
  1545         -          if (wantDefaultValue)
  1546         -          {
  1547         -            // Determine the default value for the column, which sucks because we have to query the schema for each column
  1548         -            using (SQLiteCommand cmdTable = new SQLiteCommand(HelperMethods.StringFormat(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
  1549         -              baseCatalogName,
  1550         -              baseTableName
  1551         -              ), _command.Connection))
  1552         -            using (DbDataReader rdTable = cmdTable.ExecuteReader())
  1553         -            {
  1554         -              // Find the matching column
  1555         -              while (rdTable.Read())
  1556         -              {
  1557         -                if (String.Compare(baseColumnName, rdTable.GetString(1), StringComparison.OrdinalIgnoreCase) == 0)
         1489  +                string baseCatalogName = String.Empty;
         1490  +
         1491  +                if (row[SchemaTableOptionalColumn.BaseCatalogName] != DBNull.Value)
         1492  +                    baseCatalogName = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
         1493  +
         1494  +                string baseTableName = String.Empty;
         1495  +
         1496  +                if (row[SchemaTableColumn.BaseTableName] != DBNull.Value)
         1497  +                    baseTableName = (string)row[SchemaTableColumn.BaseTableName];
         1498  +
         1499  +                if (sql.DoesTableExist(baseCatalogName, baseTableName))
         1500  +                {
         1501  +                    string baseColumnName = String.Empty;
         1502  +
         1503  +                    if (row[SchemaTableColumn.BaseColumnName] != DBNull.Value)
         1504  +                        baseColumnName = (string)row[SchemaTableColumn.BaseColumnName];
         1505  +
         1506  +                    string collSeq = null;
         1507  +                    bool bNotNull = false;
         1508  +                    bool bPrimaryKey = false;
         1509  +                    bool bAutoIncrement = false;
         1510  +                    string[] arSize;
         1511  +
         1512  +                    // Get the column meta data
         1513  +                    _command.Connection._sql.ColumnMetaData(
         1514  +                        baseCatalogName,
         1515  +                        baseTableName,
         1516  +                        strColumn,
         1517  +                        true,
         1518  +                        ref dataType, ref collSeq, ref bNotNull, ref bPrimaryKey, ref bAutoIncrement);
         1519  +
         1520  +                    if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
         1521  +                    bool allowDbNull = (bool)row[SchemaTableColumn.AllowDBNull];
         1522  +
         1523  +                    row[SchemaTableColumn.IsKey] = bPrimaryKey && CountParents(parentToColumns) <= 1;
         1524  +                    row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
         1525  +                    row["CollationType"] = collSeq;
         1526  +
         1527  +                    // For types like varchar(50) and such, extract the size
         1528  +                    arSize = dataType.Split('(');
         1529  +                    if (arSize.Length > 1)
         1530  +                    {
         1531  +                        dataType = arSize[0];
         1532  +                        arSize = arSize[1].Split(')');
         1533  +                        if (arSize.Length > 1)
         1534  +                        {
         1535  +                            arSize = arSize[0].Split(',', '.');
         1536  +                            if (sqlType.Type == DbType.Binary || SQLiteConvert.IsStringDbType(sqlType.Type))
         1537  +                            {
         1538  +                                row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
         1539  +                            }
         1540  +                            else
         1541  +                            {
         1542  +                                row[SchemaTableColumn.NumericPrecision] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
         1543  +                                if (arSize.Length > 1)
         1544  +                                    row[SchemaTableColumn.NumericScale] = Convert.ToInt32(arSize[1], CultureInfo.InvariantCulture);
         1545  +                            }
         1546  +                        }
         1547  +                    }
         1548  +
         1549  +                    if (wantDefaultValue)
         1550  +                    {
         1551  +                        // Determine the default value for the column, which sucks because we have to query the schema for each column
         1552  +                        using (SQLiteCommand cmdTable = new SQLiteCommand(HelperMethods.StringFormat(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
         1553  +                            baseCatalogName,
         1554  +                            baseTableName
         1555  +                        ), _command.Connection))
         1556  +                        using (DbDataReader rdTable = cmdTable.ExecuteReader())
         1557  +                        {
         1558  +                            // Find the matching column
         1559  +                            while (rdTable.Read())
         1560  +                            {
         1561  +                                if (String.Compare(baseColumnName, rdTable.GetString(1), StringComparison.OrdinalIgnoreCase) == 0)
         1562  +                                {
         1563  +                                    if (rdTable.IsDBNull(4) == false)
         1564  +                                        row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];
         1565  +
         1566  +                                    break;
         1567  +                                }
         1568  +                            }
         1569  +                        }
         1570  +                    }
         1571  +
         1572  +                    // Determine IsUnique properly, which is a pain in the butt!
         1573  +                    if (wantUniqueInfo)
         1574  +                    {
         1575  +                        if (baseCatalogName != strCatalog || baseTableName != strTable)
         1576  +                        {
         1577  +                            strCatalog = baseCatalogName;
         1578  +                            strTable = baseTableName;
         1579  +
         1580  +                            tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
         1581  +                                baseCatalogName,
         1582  +                                null,
         1583  +                                baseTableName,
         1584  +                                null
         1585  +                            });
         1586  +                        }
         1587  +
         1588  +                        foreach (DataRow rowIndexes in tblIndexes.Rows)
         1589  +                        {
         1590  +                            tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
         1591  +                                baseCatalogName,
         1592  +                                null,
         1593  +                                baseTableName,
         1594  +                                (string)rowIndexes["INDEX_NAME"],
         1595  +                                null
         1596  +                            });
         1597  +                            foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
         1598  +                            {
         1599  +                                if (String.Compare(SQLiteConvert.GetStringOrNull(rowColumnIndex["COLUMN_NAME"]), strColumn, StringComparison.OrdinalIgnoreCase) == 0)
         1600  +                                {
         1601  +                                    //
         1602  +                                    // BUGFIX: Make sure that we only flag this column as "unique"
         1603  +                                    //         if we are not processing of some kind of multi-table
         1604  +                                    //         construct (i.e. a join) because in that case we must
         1605  +                                    //         allow duplicate values (refer to ticket [7e3fa93744]).
         1606  +                                    //
         1607  +                                    if (parentToColumns.Count == 1 && tblIndexColumns.Rows.Count == 1 && allowDbNull == false)
         1608  +                                        row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];
         1609  +
         1610  +                                    // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
         1611  +                                    // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
         1612  +                                    //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
         1613  +                                    //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.
         1614  +
         1615  +                                    //if (tblIndexColumns.Rows.Count == 1 && (bool)rowIndexes["PRIMARY_KEY"] == true && String.IsNullOrEmpty(dataType) == false &&
         1616  +                                    //  String.Compare(dataType, "integer", StringComparison.OrdinalIgnoreCase) == 0)
         1617  +                                    //{
         1618  +                                    //    //  row[SchemaTableOptionalColumn.IsAutoIncrement] = true;
         1619  +                                    //}
         1620  +
         1621  +                                    break;
         1622  +                                }
         1623  +                            }
         1624  +                        }
         1625  +                    }
         1626  +                }
         1627  +
         1628  +                if (String.IsNullOrEmpty(dataType))
  1558   1629                   {
  1559         -                  if (rdTable.IsDBNull(4) == false)
  1560         -                    row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];
  1561         -
  1562         -                  break;
         1630  +                    TypeAffinity affin = TypeAffinity.Uninitialized;
         1631  +                    dataType = _activeStatement._sql.ColumnType(_activeStatement, n, ref affin);
  1563   1632                   }
  1564         -              }
  1565         -            }
  1566         -          }
  1567   1633   
  1568         -          // Determine IsUnique properly, which is a pain in the butt!
  1569         -          if (wantUniqueInfo)
  1570         -          {
  1571         -            if (baseCatalogName != strCatalog
  1572         -              || baseTableName != strTable)
  1573         -            {
  1574         -              strCatalog = baseCatalogName;
  1575         -              strTable = baseTableName;
  1576         -
  1577         -              tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
  1578         -                baseCatalogName,
  1579         -                null,
  1580         -                baseTableName,
  1581         -                null });
         1634  +                if (String.IsNullOrEmpty(dataType) == false)
         1635  +                    row["DataTypeName"] = dataType;
  1582   1636               }
  1583   1637   
  1584         -            foreach (DataRow rowIndexes in tblIndexes.Rows)
  1585         -            {
  1586         -              tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
  1587         -                baseCatalogName,
  1588         -                null,
  1589         -                baseTableName,
  1590         -                (string)rowIndexes["INDEX_NAME"],
  1591         -                null
  1592         -                });
  1593         -              foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
  1594         -              {
  1595         -                if (String.Compare(SQLiteConvert.GetStringOrNull(rowColumnIndex["COLUMN_NAME"]), strColumn, StringComparison.OrdinalIgnoreCase) == 0)
  1596         -                {
  1597         -                  //
  1598         -                  // BUGFIX: Make sure that we only flag this column as "unique"
  1599         -                  //         if we are not processing of some kind of multi-table
  1600         -                  //         construct (i.e. a join) because in that case we must
  1601         -                  //         allow duplicate values (refer to ticket [7e3fa93744]).
  1602         -                  //
  1603         -                  if (parentToColumns.Count == 1 && tblIndexColumns.Rows.Count == 1 && allowDbNull == false)
  1604         -                    row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];
  1605         -
  1606         -                  // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
  1607         -                  // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
  1608         -                  //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
  1609         -                  //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.
  1610         -
  1611         -                  if (tblIndexColumns.Rows.Count == 1 && (bool)rowIndexes["PRIMARY_KEY"] == true && String.IsNullOrEmpty(dataType) == false &&
  1612         -                    String.Compare(dataType, "integer", StringComparison.OrdinalIgnoreCase) == 0)
  1613         -                  {
  1614         -                    //  row[SchemaTableOptionalColumn.IsAutoIncrement] = true;
  1615         -                  }
  1616         -
  1617         -                  break;
  1618         -                }
  1619         -              }
  1620         -            }
  1621         -          }
  1622         -
  1623         -          if (String.IsNullOrEmpty(dataType))
  1624         -          {
  1625         -            TypeAffinity affin = TypeAffinity.Uninitialized;
  1626         -            dataType = _activeStatement._sql.ColumnType(_activeStatement, n, ref affin);
  1627         -          }
  1628         -
  1629         -          if (String.IsNullOrEmpty(dataType) == false)
  1630         -            row["DataTypeName"] = dataType;
  1631         -        }
  1632         -        tbl.Rows.Add(row);
  1633         -      }
  1634         -
  1635         -      if (_keyInfo != null)
  1636         -        _keyInfo.AppendSchemaTable(tbl);
  1637         -
  1638         -      tbl.AcceptChanges();
  1639         -      tbl.EndLoadData();
  1640         -
  1641         -      return tbl;
         1638  +            tbl.Rows.Add(row);
         1639  +        }
         1640  +
         1641  +        if (_keyInfo != null)
         1642  +            _keyInfo.AppendSchemaTable(tbl);
         1643  +
         1644  +        tbl.AcceptChanges();
         1645  +        tbl.EndLoadData();
         1646  +
         1647  +        return tbl;
  1642   1648       }
  1643   1649   
  1644   1650       /// <summary>
  1645   1651       /// Retrieves the column as a string
  1646   1652       /// </summary>
  1647   1653       /// <param name="i">The index of the column.</param>
  1648   1654       /// <returns>string</returns>