using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Npgsql.BackendMessages;
namespace Npgsql
{
///
/// Represents a single SQL statement within Npgsql.
///
/// Instances aren't constructed directly; users should construct an
/// object and populate its property as in standard ADO.NET.
/// Npgsql will analyze that property and construct instances of
/// internally.
///
/// Users can retrieve instances from
/// and access information about statement execution (e.g. affected rows).
///
public sealed class NpgsqlStatement
{
///
/// The SQL text of the statement.
///
public string SQL { get; set; } = string.Empty;
///
/// Specifies the type of query, e.g. SELECT.
///
public StatementType StatementType { get; internal set; }
///
/// The number of rows affected or retrieved.
///
///
/// See the command tag in the CommandComplete message,
/// https://www.postgresql.org/docs/current/static/protocol-message-formats.html
///
public uint Rows => (uint)LongRows;
///
/// The number of rows affected or retrieved.
///
///
/// See the command tag in the CommandComplete message,
/// https://www.postgresql.org/docs/current/static/protocol-message-formats.html
///
public ulong LongRows { get; internal set; }
///
/// For an INSERT, the object ID of the inserted row if is 1 and
/// the target table has OIDs; otherwise 0.
///
public uint OID { get; internal set; }
///
/// The input parameters sent with this statement.
///
public List InputParameters
{
get => _inputParameters ??= _ownedInputParameters ??= new();
internal set => _inputParameters = value;
}
List? _ownedInputParameters;
List? _inputParameters;
///
/// The RowDescription message for this query. If null, the query does not return rows (e.g. INSERT)
///
internal RowDescriptionMessage? Description
{
get => PreparedStatement == null ? _description : PreparedStatement.Description;
set
{
if (PreparedStatement == null)
_description = value;
else
PreparedStatement.Description = value;
}
}
RowDescriptionMessage? _description;
///
/// If this statement has been automatically prepared, references the .
/// Null otherwise.
///
internal PreparedStatement? PreparedStatement
{
get => _preparedStatement != null && _preparedStatement.State == PreparedState.Unprepared
? _preparedStatement = null
: _preparedStatement;
set => _preparedStatement = value;
}
PreparedStatement? _preparedStatement;
internal bool IsPreparing;
///
/// Holds the server-side (prepared) statement name. Empty string for non-prepared statements.
///
internal string StatementName => PreparedStatement?.Name ?? "";
///
/// Whether this statement has already been prepared (including automatic preparation).
///
internal bool IsPrepared => PreparedStatement?.IsPrepared == true;
internal void Reset()
{
SQL = string.Empty;
StatementType = StatementType.Select;
_description = null;
LongRows = 0;
OID = 0;
PreparedStatement = null;
if (ReferenceEquals(_inputParameters, _ownedInputParameters))
InputParameters.Clear();
else if (_inputParameters is not null)
_inputParameters = null; // We're pointing at a user's NpgsqlParameterCollection
Debug.Assert(_inputParameters is null || _inputParameters.Count == 0);
Debug.Assert(_ownedInputParameters is null || _ownedInputParameters.Count == 0);
}
internal void ApplyCommandComplete(CommandCompleteMessage msg)
{
StatementType = msg.StatementType;
LongRows = msg.Rows;
OID = msg.OID;
}
///
/// Returns the SQL text of the statement.
///
public override string ToString() => SQL ?? "";
}
}