using System;
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using NpgsqlTypes;
namespace Npgsql;
///
/// This class is responsible to create database commands for automatic insert, update and delete operations.
///
[System.ComponentModel.DesignerCategory("")]
public sealed class NpgsqlCommandBuilder : DbCommandBuilder
{
// Commented out because SetRowUpdatingHandler() is commented, and causes an "is never used" warning
// private NpgsqlRowUpdatingEventHandler rowUpdatingHandler;
///
/// Initializes a new instance of the class.
///
public NpgsqlCommandBuilder()
: this(null)
{
}
///
/// Initializes a new instance of the class.
///
/// The adapter.
public NpgsqlCommandBuilder(NpgsqlDataAdapter? adapter)
{
DataAdapter = adapter;
QuotePrefix = "\"";
QuoteSuffix = "\"";
}
///
/// Gets or sets the beginning character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
///
///
/// The beginning character or characters to use. The default is an empty string.
///
[AllowNull]
public override string QuotePrefix
{
get => base.QuotePrefix;
// TODO: Why should it be possible to remove the QuotePrefix?
set
{
if (string.IsNullOrEmpty(value))
{
base.QuotePrefix = value;
}
else
{
base.QuotePrefix = "\"";
}
}
}
///
/// Gets or sets the ending character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
///
///
/// The ending character or characters to use. The default is an empty string.
///
[AllowNull]
public override string QuoteSuffix
{
get => base.QuoteSuffix;
// TODO: Why should it be possible to remove the QuoteSuffix?
set
{
if (string.IsNullOrEmpty(value))
{
base.QuoteSuffix = value;
}
else
{
base.QuoteSuffix = "\"";
}
}
}
///
///
/// This method is responsible to derive the command parameter list with values obtained from function definition.
/// It clears the Parameters collection of command. Also, if there is any parameter type which is not supported by Npgsql, an InvalidOperationException will be thrown.
/// Parameters name will be parameter1, parameter2, ... for CommandType.StoredProcedure and named after the placeholder for CommandType.Text
///
/// NpgsqlCommand whose function parameters will be obtained.
public static void DeriveParameters(NpgsqlCommand command) => command.DeriveParameters();
///
/// Gets the automatically generated object required
/// to perform insertions at the data source.
///
///
/// The automatically generated object required to perform insertions.
///
public new NpgsqlCommand GetInsertCommand() => GetInsertCommand(false);
///
/// Gets the automatically generated object required to perform insertions
/// at the data source, optionally using columns for parameter names.
///
///
/// If , generate parameter names matching column names, if possible.
/// If , generate @p1, @p2, and so on.
///
///
/// The automatically generated object required to perform insertions.
///
public new NpgsqlCommand GetInsertCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand) base.GetInsertCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
///
/// Gets the automatically generated System.Data.Common.DbCommand object required
/// to perform updates at the data source.
///
///
/// The automatically generated System.Data.Common.DbCommand object required to perform updates.
///
public new NpgsqlCommand GetUpdateCommand() => GetUpdateCommand(false);
///
/// Gets the automatically generated object required to perform updates
/// at the data source, optionally using columns for parameter names.
///
///
/// If , generate parameter names matching column names, if possible.
/// If , generate @p1, @p2, and so on.
///
///
/// The automatically generated object required to perform updates.
///
public new NpgsqlCommand GetUpdateCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand)base.GetUpdateCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
///
/// Gets the automatically generated System.Data.Common.DbCommand object required
/// to perform deletions at the data source.
///
///
/// The automatically generated System.Data.Common.DbCommand object required to perform deletions.
///
public new NpgsqlCommand GetDeleteCommand() => GetDeleteCommand(false);
///
/// Gets the automatically generated object required to perform deletions
/// at the data source, optionally using columns for parameter names.
///
///
/// If , generate parameter names matching column names, if possible.
/// If , generate @p1, @p2, and so on.
///
///
/// The automatically generated object required to perform deletions.
///
public new NpgsqlCommand GetDeleteCommand(bool useColumnsForParameterNames)
{
var cmd = (NpgsqlCommand) base.GetDeleteCommand(useColumnsForParameterNames);
cmd.UpdatedRowSource = UpdateRowSource.None;
return cmd;
}
//never used
//private string QualifiedTableName(string schema, string tableName)
//{
// if (schema == null || schema.Length == 0)
// {
// return tableName;
// }
// else
// {
// return schema + "." + tableName;
// }
//}
/*
private static void SetParameterValuesFromRow(NpgsqlCommand command, DataRow row)
{
foreach (NpgsqlParameter parameter in command.Parameters)
{
parameter.Value = row[parameter.SourceColumn, parameter.SourceVersion];
}
}
*/
///
/// Applies the parameter information.
///
/// The parameter.
/// The row.
/// Type of the statement.
/// If set to [where clause].
protected override void ApplyParameterInfo(DbParameter p, DataRow row, System.Data.StatementType statementType, bool whereClause)
{
var param = (NpgsqlParameter)p;
param.NpgsqlDbType = (NpgsqlDbType)row[SchemaTableColumn.ProviderType];
}
///
/// Returns the name of the specified parameter in the format of @p#.
///
/// The number to be included as part of the parameter's name..
///
/// The name of the parameter with the specified number appended as part of the parameter name.
///
protected override string GetParameterName(int parameterOrdinal)
=> string.Format(CultureInfo.InvariantCulture, "@p{0}", parameterOrdinal);
///
/// Returns the full parameter name, given the partial parameter name.
///
/// The partial name of the parameter.
///
/// The full parameter name corresponding to the partial parameter name requested.
///
protected override string GetParameterName(string parameterName)
=> string.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
///
/// Returns the placeholder for the parameter in the associated SQL statement.
///
/// The number to be included as part of the parameter's name.
///
/// The name of the parameter with the specified number appended.
///
protected override string GetParameterPlaceholder(int parameterOrdinal)
=> GetParameterName(parameterOrdinal);
///
/// Registers the to handle the event for a .
///
/// The to be used for the update.
protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
{
var npgsqlAdapter = adapter as NpgsqlDataAdapter;
if (npgsqlAdapter == null)
throw new ArgumentException("adapter needs to be a NpgsqlDataAdapter", nameof(adapter));
// Being called twice for the same adapter means unregister
if (adapter == DataAdapter)
npgsqlAdapter.RowUpdating -= RowUpdatingHandler;
else
npgsqlAdapter.RowUpdating += RowUpdatingHandler;
}
///
/// Adds an event handler for the event.
///
/// The sender
/// A instance containing information about the event.
void RowUpdatingHandler(object sender, NpgsqlRowUpdatingEventArgs e) => base.RowUpdatingHandler(e);
///
/// Given an unquoted identifier in the correct catalog case, returns the correct quoted form of that identifier, including properly escaping any embedded quotes in the identifier.
///
/// The original unquoted identifier.
///
/// The quoted version of the identifier. Embedded quotes within the identifier are properly escaped.
///
/// Unquoted identifier parameter cannot be null
public override string QuoteIdentifier(string unquotedIdentifier)
=> unquotedIdentifier == null
? throw new ArgumentNullException(nameof(unquotedIdentifier), "Unquoted identifier parameter cannot be null")
: $"{QuotePrefix}{unquotedIdentifier.Replace(QuotePrefix, QuotePrefix + QuotePrefix)}{QuoteSuffix}";
///
/// Given a quoted identifier, returns the correct unquoted form of that identifier, including properly un-escaping any embedded quotes in the identifier.
///
/// The identifier that will have its embedded quotes removed.
///
/// The unquoted identifier, with embedded quotes properly un-escaped.
///
/// Quoted identifier parameter cannot be null
public override string UnquoteIdentifier(string quotedIdentifier)
{
if (quotedIdentifier == null)
throw new ArgumentNullException(nameof(quotedIdentifier), "Quoted identifier parameter cannot be null");
var unquotedIdentifier = quotedIdentifier.Trim().Replace(QuotePrefix + QuotePrefix, QuotePrefix);
if (unquotedIdentifier.StartsWith(QuotePrefix, StringComparison.Ordinal))
unquotedIdentifier = unquotedIdentifier.Remove(0, 1);
if (unquotedIdentifier.EndsWith(QuoteSuffix, StringComparison.Ordinal))
unquotedIdentifier = unquotedIdentifier.Remove(unquotedIdentifier.Length - 1, 1);
return unquotedIdentifier;
}
}