using GB5Shared.DTO.Framework.SchemaIntrospection; using SwDAL.DTO.ClientDatabase; using SwDAL.DTO.DbServer; using SwDAL.Enums; namespace SwBLL.Provisioning; /// /// Executes SQL against a remote target database using credentials from DbServerDTO. /// Never uses Integrated Security — always SqlConnectionStringBuilder with Username/Password. /// public interface ITargetDbExecutor { /// Executes a DDL or batch script (GO-separated) against the target database. Returns rows affected. Task ExecuteScriptAsync(string connectionString, string sql, CancellationToken ct); /// Executes a single parameterized DML statement (INSERT/UPDATE/DELETE). Returns rows affected. Task ExecuteDmlAsync(string connectionString, string sql, Dictionary parameters, CancellationToken ct); /// /// Executes a SELECT-only query. Row cap: 5000. Throws if cap exceeded or non-SELECT detected. /// Task>> ExecuteQueryAsync( string connectionString, string sql, Dictionary parameters, CancellationToken ct); /// Builds a connection string from DbServerDTO credentials. Never Integrated Security. /// When dbUsername/dbPassword are not supplied, falls back to the DbServer's own admin /// credential — server.DbPassword is decrypted internally in that case (it is stored /// encrypted in MSWDBSERVER). string BuildConnectionString(DbServerDTO server, string databaseName, string? dbUsername = null, string? dbPassword = null); /// Builds a connection string using the least-privilege contained-user credential /// for the given role (Dba/App/ReadOnly), read from the Vault path recorded on /// ClientDatabaseDTO. If no credential has been provisioned for that role (e.g. a client /// database registered outside SqlWorkbench's own provisioner), falls back to the DbServer /// admin credential and logs a warning. Task BuildConnectionStringForRoleAsync( DbServerDTO server, ClientDatabaseDTO clientDb, ClientDbLoginRole role, CancellationToken ct); /// Builds a connection string pointed at the server's admin database (SQL Server: /// "master") rather than a specific client database — needed for RESTORE DATABASE/CREATE /// DATABASE/ALTER DATABASE, which must run before the target database exists or while it's /// not the current database context. string BuildAdminConnectionString(DbServerDTO server); /// Introspects the schema of a remote database and returns object metadata. Task> GetServerObjectsAsync( string connectionString, CancellationToken ct); /// Checks whether a database with this name already exists on the server the admin /// connection string points at. Used before RESTORE DATABASE ... WITH REPLACE (which silently /// overwrites an existing database of the same name) and before CREATE DATABASE, so a naming /// collision is refused with a clear error instead of destroying or racing an existing database. Task DatabaseExistsAsync(string adminConnectionString, string databaseName, CancellationToken ct); /// Introspects table/column metadata for a registered client database — the schema /// browsing step of the Analytics Catalog Wizard. dbType follows SwDAL.Enums.DbType /// (0=SqlServer, 1=PostgreSQL, 2=MySQL, 3=Oracle); only SqlServer is implemented today. Task> GetServerColumnsAsync( string connectionString, byte dbType, CancellationToken ct); /// Introspects foreign-key relationships for a registered client database — used by /// the Analytics Catalog Wizard to suggest joins between tables. dbType follows /// SwDAL.Enums.DbType (0=SqlServer, 1=PostgreSQL, 2=MySQL, 3=Oracle); only SqlServer is /// implemented today. Task> GetServerForeignKeysAsync( string connectionString, byte dbType, CancellationToken ct); /// /// Executes a fully self-contained, possibly multi-statement, server-assembled SQL batch /// (e.g. SELECT ... INTO #temp; SELECT ... FROM #temp) as ONE command on ONE /// connection, so a temp table created by an early statement in the batch remains visible to /// a later statement in the same batch — something 's /// per-call-fresh-connection model cannot do. /// /// This method is for pre-validated, server-assembled SQL text built by trusted BLL code /// (e.g. the Analytics report-execution engine) — NEVER for raw end-user-supplied SQL. It is /// not exposed via any SL/FastEndpoint route and must never be. /// /// The SELECT-only guard is applied to the full batch text, same as /// . Row cap defaults to a higher internal cap /// (InternalBatchRowCap = 100,000) than the 5,000-row SelectRowCap used by /// , since this path is meant for full report execution rather /// than ad-hoc exploration; callers may pass to tighten it /// further (e.g. to honor an explicit page size). /// Task>> ExecuteQueryBatchAsync( string connectionString, string sql, Dictionary parameters, int? rowCapOverride, CancellationToken ct); } /// Remote database object metadata (table, view, procedure, function). public class RemoteDbObjectDTO { public string SchemaName { get; set; } = string.Empty; public string ObjectName { get; set; } = string.Empty; public string ObjectType { get; set; } = string.Empty; // TABLE, VIEW, PROCEDURE, FUNCTION }