insertSelect method

Future<MssqlWriteOutcome> insertSelect({
  1. required List<String> columns,
  2. required MssqlSelectQuery query,
  3. List<MssqlCte> ctes = const <MssqlCte>[],
})

INSERT … SELECT, with the statement's WITH clause where T-SQL wants it: at the very start, before INSERT.

Returns the driver's count rather than a captured one. A set-based insert has no single row to read back, and counting its output rows would mean materialising the whole set on the client for a number the caller can also get from the target table.

Implementation

Future<MssqlWriteOutcome> insertSelect({
  required List<String> columns,
  required MssqlSelectQuery query,
  List<MssqlCte> ctes = const <MssqlCte>[],
}) async {
  for (final name in columns) {
    final column = binding.column(name);
    if (column == null) {
      throw ArgumentError.value(
        name,
        'columns',
        'Names a column ${binding.qualifiedName} does not have.',
      );
    }
    if (!column.writable) {
      throw ArgumentError.value(
        name,
        'columns',
        column.isReadOnly
            ? 'Is marked read-only by the generator configuration.'
            : 'Is written by the server (identity, computed or rowversion), '
                  'so a projected value has nowhere to land.',
      );
    }
  }
  var insert = MssqlInsert.intoParts(binding.nameParts).using(columns, query);
  for (final cte in ctes) {
    insert = insert.withExpression(cte);
  }
  final statement = insert.compile(dialect: dialect);
  if (triggers == MssqlTriggerKind.none) {
    return _executeCounted(statement.sql, statement.parameters);
  }
  final affected = await session.execute(
    statement.sql,
    parameters: statement.parameters,
  );
  _note();
  return MssqlWriteOutcome(
    affectedRows: affected,
    affectedRowsSource: MssqlAffectedRowsSource.driverTotal,
  );
}