private DataTable Schema_Indexes(string strCatalog, string strTable, string strIndex)
{
DataTable tbl = new DataTable("Indexes");
DataRow row;
List<int> primaryKeys = new List<int>();
bool maybeRowId;
tbl.Locale = CultureInfo.InvariantCulture;
tbl.Columns.Add("TABLE_CATALOG", typeof(string));
tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
tbl.Columns.Add("TABLE_NAME", typeof(string));
tbl.Columns.Add("INDEX_CATALOG", typeof(string));
tbl.Columns.Add("INDEX_SCHEMA", typeof(string));
tbl.Columns.Add("INDEX_NAME", typeof(string));
tbl.Columns.Add("PRIMARY_KEY", typeof(bool));
tbl.Columns.Add("UNIQUE", typeof(bool));
tbl.Columns.Add("CLUSTERED", typeof(bool));
tbl.Columns.Add("TYPE", typeof(int));
tbl.Columns.Add("FILL_FACTOR", typeof(int));
tbl.Columns.Add("INITIAL_SIZE", typeof(int));
tbl.Columns.Add("NULLS", typeof(int));
tbl.Columns.Add("SORT_BOOKMARKS", typeof(bool));
tbl.Columns.Add("AUTO_UPDATE", typeof(bool));
tbl.Columns.Add("NULL_COLLATION", typeof(int));
tbl.Columns.Add("ORDINAL_POSITION", typeof(int));
tbl.Columns.Add("COLUMN_NAME", typeof(string));
tbl.Columns.Add("COLUMN_GUID", typeof(Guid));
tbl.Columns.Add("COLUMN_PROPID", typeof(long));
tbl.Columns.Add("COLLATION", typeof(short));
tbl.Columns.Add("CARDINALITY", typeof(Decimal));
tbl.Columns.Add("PAGES", typeof(int));
tbl.Columns.Add("FILTER_CONDITION", typeof(string));
tbl.Columns.Add("INTEGRATED", typeof(bool));
tbl.Columns.Add("INDEX_DEFINITION", typeof(string));
tbl.BeginLoadData();
if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
string master = (String.Compare(strCatalog, "temp", true, CultureInfo.InvariantCulture) == 0) ? _tempmasterdb : _masterdb;
using (SqliteCommand cmdTables = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{1}] WHERE [type] LIKE 'table'", strCatalog, master), this))
using (SqliteDataReader rdTables = cmdTables.ExecuteReader())
{
while (rdTables.Read())
{
maybeRowId = false;
primaryKeys.Clear();
if (String.IsNullOrEmpty(strTable) || String.Compare(rdTables.GetString(2), strTable, true, CultureInfo.InvariantCulture) == 0)
{
// First, look for any rowid indexes -- which sqlite defines are INTEGER PRIMARY KEY columns.
// Such indexes are not listed in the indexes list but count as indexes just the same.
try
{
using (SqliteCommand cmdTable = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].table_info([{1}])", strCatalog, rdTables.GetString(2)), this))
using (SqliteDataReader rdTable = cmdTable.ExecuteReader())
{
while (rdTable.Read())
{
if (rdTable.GetInt32(5) == 1)
{
primaryKeys.Add(rdTable.GetInt32(0));
// If the primary key is of type INTEGER, then its a rowid and we need to make a fake index entry for it.
if (String.Compare(rdTable.GetString(2), "INTEGER", true, CultureInfo.InvariantCulture) == 0)
maybeRowId = true;
}
}
}
}
catch (SqliteException)
{
}
if (primaryKeys.Count == 1 && maybeRowId == true)
{
row = tbl.NewRow();
row["TABLE_CATALOG"] = strCatalog;
row["TABLE_NAME"] = rdTables.GetString(2);
row["INDEX_CATALOG"] = strCatalog;
row["PRIMARY_KEY"] = true;
row["INDEX_NAME"] = String.Format(CultureInfo.InvariantCulture, "{1}_PK_{0}", rdTables.GetString(2), master);
row["UNIQUE"] = true;
if (String.Compare((string)row["INDEX_NAME"], strIndex, true, CultureInfo.InvariantCulture) == 0
|| strIndex == null)
{
tbl.Rows.Add(row);
}
primaryKeys.Clear();
}
// Now fetch all the rest of the indexes.
try
{
using (SqliteCommand cmd = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].index_list([{1}])", strCatalog, rdTables.GetString(2)), this))
using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader())
{
while (rd.Read())
{
if (String.Compare(rd.GetString(1), strIndex, true, CultureInfo.InvariantCulture) == 0
|| strIndex == null)
{
row = tbl.NewRow();
row["TABLE_CATALOG"] = strCatalog;
row["TABLE_NAME"] = rdTables.GetString(2);
row["INDEX_CATALOG"] = strCatalog;
row["INDEX_NAME"] = rd.GetString(1);
row["UNIQUE"] = rd.GetBoolean(2);
row["PRIMARY_KEY"] = false;
// get the index definition
using (SqliteCommand cmdIndexes = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{2}] WHERE [type] LIKE 'index' AND [name] LIKE '{1}'", strCatalog, rd.GetString(1).Replace("'", "''"), master), this))
using (SqliteDataReader rdIndexes = cmdIndexes.ExecuteReader())
{
while (rdIndexes.Read())
{
if (rdIndexes.IsDBNull(4) == false)
row["INDEX_DEFINITION"] = rdIndexes.GetString(4);
break;
}
}
// Now for the really hard work. Figure out which index is the primary key index.
// The only way to figure it out is to check if the index was an autoindex and if we have a non-rowid
// primary key, and all the columns in the given index match the primary key columns
if (primaryKeys.Count > 0 && rd.GetString(1).StartsWith("sqlite_autoindex_" + rdTables.GetString(2), StringComparison.InvariantCultureIgnoreCase) == true)
{
using (SqliteCommand cmdDetails = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].index_info([{1}])", strCatalog, rd.GetString(1)), this))
using (SqliteDataReader rdDetails = cmdDetails.ExecuteReader())
{
int nMatches = 0;
while (rdDetails.Read())
{
if (primaryKeys.Contains(rdDetails.GetInt32(1)) == false)
{
nMatches = 0;
break;
}
nMatches++;
}
if (nMatches == primaryKeys.Count)
{
row["PRIMARY_KEY"] = true;
primaryKeys.Clear();
}
}
}
tbl.Rows.Add(row);
}
}
}
}
catch (SqliteException)
{
}
}
}
}
tbl.AcceptChanges();
tbl.EndLoadData();
return tbl;
}