/******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) * * Released to the public domain, use at your own risk! ********************************************************/ namespace System.Data.SQLite { using System; using System.Data; using System.Data.Common; using System.Globalization; using System.ComponentModel; /// /// SQLite implementation of DbCommandBuilder. /// public sealed class SQLiteCommandBuilder : DbCommandBuilder { /// /// Default constructor /// public SQLiteCommandBuilder() : this(null) { } /// /// Initializes the command builder and associates it with the specified data adapter. /// /// public SQLiteCommandBuilder(SQLiteDataAdapter adp) { QuotePrefix = "["; QuoteSuffix = "]"; DataAdapter = adp; } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) throw new ObjectDisposedException(typeof(SQLiteCommandBuilder).Name); #endif } /////////////////////////////////////////////////////////////////////////////////////////////// /// /// Cleans up resources (native and managed) associated with the current instance. /// /// /// Zero when being disposed via garbage collection; otherwise, non-zero. /// protected override void Dispose(bool disposing) { try { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// } } finally { base.Dispose(disposing); // // NOTE: Everything should be fully disposed at this point. // disposed = true; } } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// /// /// Minimal amount of parameter processing. Primarily sets the DbType for the parameter equal to the provider type in the schema /// /// The parameter to use in applying custom behaviors to a row /// The row to apply the parameter to /// The type of statement /// Whether the application of the parameter is part of a WHERE clause protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, StatementType statementType, bool whereClause) { SQLiteParameter param = (SQLiteParameter)parameter; param.DbType = (DbType)row[SchemaTableColumn.ProviderType]; } /// /// Returns a valid named parameter /// /// The name of the parameter /// Error protected override string GetParameterName(string parameterName) { return HelperMethods.StringFormat(CultureInfo.InvariantCulture, "@{0}", parameterName); } /// /// Returns a named parameter for the given ordinal /// /// The i of the parameter /// Error protected override string GetParameterName(int parameterOrdinal) { return HelperMethods.StringFormat(CultureInfo.InvariantCulture, "@param{0}", parameterOrdinal); } /// /// Returns a placeholder character for the specified parameter i. /// /// The index of the parameter to provide a placeholder for /// Returns a named parameter protected override string GetParameterPlaceholder(int parameterOrdinal) { return GetParameterName(parameterOrdinal); } /// /// Sets the handler for receiving row updating events. Used by the DbCommandBuilder to autogenerate SQL /// statements that may not have previously been generated. /// /// A data adapter to receive events on. protected override void SetRowUpdatingHandler(DbDataAdapter adapter) { if (adapter == base.DataAdapter) { ((SQLiteDataAdapter)adapter).RowUpdating -= new EventHandler(RowUpdatingEventHandler); } else { ((SQLiteDataAdapter)adapter).RowUpdating += new EventHandler(RowUpdatingEventHandler); } } private void RowUpdatingEventHandler(object sender, RowUpdatingEventArgs e) { base.RowUpdatingHandler(e); } /// /// Gets/sets the DataAdapter for this CommandBuilder /// public new SQLiteDataAdapter DataAdapter { get { CheckDisposed(); return (SQLiteDataAdapter)base.DataAdapter; } set { CheckDisposed(); base.DataAdapter = value; } } /// /// Returns the automatically-generated SQLite command to delete rows from the database /// /// public new SQLiteCommand GetDeleteCommand() { CheckDisposed(); return (SQLiteCommand)base.GetDeleteCommand(); } /// /// Returns the automatically-generated SQLite command to delete rows from the database /// /// /// public new SQLiteCommand GetDeleteCommand(bool useColumnsForParameterNames) { CheckDisposed(); return (SQLiteCommand)base.GetDeleteCommand(useColumnsForParameterNames); } /// /// Returns the automatically-generated SQLite command to update rows in the database /// /// public new SQLiteCommand GetUpdateCommand() { CheckDisposed(); return (SQLiteCommand)base.GetUpdateCommand(); } /// /// Returns the automatically-generated SQLite command to update rows in the database /// /// /// public new SQLiteCommand GetUpdateCommand(bool useColumnsForParameterNames) { CheckDisposed(); return (SQLiteCommand)base.GetUpdateCommand(useColumnsForParameterNames); } /// /// Returns the automatically-generated SQLite command to insert rows into the database /// /// public new SQLiteCommand GetInsertCommand() { CheckDisposed(); return (SQLiteCommand)base.GetInsertCommand(); } /// /// Returns the automatically-generated SQLite command to insert rows into the database /// /// /// public new SQLiteCommand GetInsertCommand(bool useColumnsForParameterNames) { CheckDisposed(); return (SQLiteCommand)base.GetInsertCommand(useColumnsForParameterNames); } /// /// Overridden to hide its property from the designer /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false)] #endif public override CatalogLocation CatalogLocation { get { CheckDisposed(); return base.CatalogLocation; } set { CheckDisposed(); base.CatalogLocation = value; } } /// /// Overridden to hide its property from the designer /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false)] #endif public override string CatalogSeparator { get { CheckDisposed(); return base.CatalogSeparator; } set { CheckDisposed(); base.CatalogSeparator = value; } } /// /// Overridden to hide its property from the designer /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false)] #endif [DefaultValue("[")] public override string QuotePrefix { get { CheckDisposed(); return base.QuotePrefix; } set { CheckDisposed(); base.QuotePrefix = value; } } /// /// Overridden to hide its property from the designer /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false)] #endif public override string QuoteSuffix { get { CheckDisposed(); return base.QuoteSuffix; } set { CheckDisposed(); base.QuoteSuffix = value; } } /// /// Places brackets around an identifier /// /// The identifier to quote /// The bracketed identifier public override string QuoteIdentifier(string unquotedIdentifier) { CheckDisposed(); if (String.IsNullOrEmpty(QuotePrefix) || String.IsNullOrEmpty(QuoteSuffix) || String.IsNullOrEmpty(unquotedIdentifier)) return unquotedIdentifier; return QuotePrefix + unquotedIdentifier.Replace(QuoteSuffix, QuoteSuffix + QuoteSuffix) + QuoteSuffix; } /// /// Removes brackets around an identifier /// /// The quoted (bracketed) identifier /// The undecorated identifier public override string UnquoteIdentifier(string quotedIdentifier) { CheckDisposed(); if (String.IsNullOrEmpty(QuotePrefix) || String.IsNullOrEmpty(QuoteSuffix) || String.IsNullOrEmpty(quotedIdentifier)) return quotedIdentifier; if (quotedIdentifier.StartsWith(QuotePrefix, StringComparison.OrdinalIgnoreCase) == false || quotedIdentifier.EndsWith(QuoteSuffix, StringComparison.OrdinalIgnoreCase) == false) return quotedIdentifier; return quotedIdentifier.Substring(QuotePrefix.Length, quotedIdentifier.Length - (QuotePrefix.Length + QuoteSuffix.Length)).Replace(QuoteSuffix + QuoteSuffix, QuoteSuffix); } /// /// Overridden to hide its property from the designer /// #if !PLATFORM_COMPACTFRAMEWORK [Browsable(false)] #endif public override string SchemaSeparator { get { CheckDisposed(); return base.SchemaSeparator; } set { CheckDisposed(); base.SchemaSeparator = value; } } /// /// Override helper, which can help the base command builder choose the right keys for the given query /// /// /// protected override DataTable GetSchemaTable(DbCommand sourceCommand) { using (IDataReader reader = sourceCommand.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly)) { DataTable schema = reader.GetSchemaTable(); // If the query contains a primary key, turn off the IsUnique property // for all the non-key columns if (HasSchemaPrimaryKey(schema)) ResetIsUniqueSchemaColumn(schema); // if table has no primary key we use unique columns as a fall back return schema; } } private bool HasSchemaPrimaryKey(DataTable schema) { DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey]; foreach (DataRow schemaRow in schema.Rows) { if ((bool)schemaRow[IsKeyColumn] == true) return true; } return false; } private void ResetIsUniqueSchemaColumn(DataTable schema) { DataColumn IsUniqueColumn = schema.Columns[SchemaTableColumn.IsUnique]; DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey]; foreach (DataRow schemaRow in schema.Rows) { if ((bool)schemaRow[IsKeyColumn] == false) schemaRow[IsUniqueColumn] = false; } schema.AcceptChanges(); } } }