diff --git a/src/Marten/IAdvancedSql.cs b/src/Marten/IAdvancedSql.cs
index dd2c22828c..5b56994c15 100644
--- a/src/Marten/IAdvancedSql.cs
+++ b/src/Marten/IAdvancedSql.cs
@@ -1,7 +1,9 @@
#nullable enable
+using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using Marten.Internal.Sessions;
namespace Marten;
@@ -20,6 +22,21 @@ public interface IAdvancedSql
///
Task> QueryAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameter can be a document class, a scalar or any JSON-serializable class.
+ /// If the result is a document, the SQL must contain a select with the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// selected.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameters can be any document class, scalar or JSON-serializable class.
@@ -35,6 +52,23 @@ public interface IAdvancedSql
///
Task> QueryAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameters can be any document class, scalar or JSON-serializable class.
+ /// For each result type parameter, the SQL SELECT statement must contain a ROW.
+ /// For document types, the row must contain the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// provided.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameters can be any document class, scalar or JSON-serializable class.
@@ -51,6 +85,24 @@ public interface IAdvancedSql
///
Task> QueryAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameters can be any document class, scalar or JSON-serializable class.
+ /// For each result type parameter, the SQL SELECT statement must contain a ROW.
+ /// For document types, the row must contain the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// provided.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameter can be a document class, a scalar or any JSON-serializable class.
@@ -62,6 +114,7 @@ public interface IAdvancedSql
///
///
///
+ [Obsolete(QuerySession.SynchronousRemoval)]
IReadOnlyList Query(string sql, params object[] parameters);
///
@@ -77,6 +130,7 @@ public interface IAdvancedSql
///
///
///
+ [Obsolete(QuerySession.SynchronousRemoval)]
IReadOnlyList<(T1, T2)> Query(string sql, params object[] parameters);
///
@@ -93,6 +147,7 @@ public interface IAdvancedSql
///
///
///
+ [Obsolete(QuerySession.SynchronousRemoval)]
IReadOnlyList<(T1, T2, T3)> Query(string sql, params object[] parameters);
///
@@ -109,6 +164,22 @@ public interface IAdvancedSql
/// An async enumerable iterating over the results
IAsyncEnumerable StreamAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameters can be any document class, scalar or JSON-serializable class.
+ /// For each result type parameter, the SQL SELECT statement must contain a ROW.
+ /// For document types, the row must contain the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// provided.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// An async enumerable iterating over the results
+ IAsyncEnumerable StreamAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameters can be any document class, scalar or JSON-serializable class.
@@ -124,6 +195,23 @@ public interface IAdvancedSql
/// An async enumerable iterating over the list of result tuples
IAsyncEnumerable<(T1, T2)> StreamAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameters can be any document class, scalar or JSON-serializable class.
+ /// For each result type parameter, the SQL SELECT statement must contain a ROW.
+ /// For document types, the row must contain the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// provided.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// An async enumerable iterating over the list of result tuples
+ IAsyncEnumerable<(T1, T2)> StreamAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameters can be any document class, scalar or JSON-serializable class.
@@ -139,4 +227,22 @@ public interface IAdvancedSql
///
/// An async enumerable iterating over the list of result tuples
IAsyncEnumerable<(T1, T2, T3)> StreamAsync(string sql, CancellationToken token, params object[] parameters);
+
+ ///
+ /// Asynchronously queries the document storage with the supplied SQL.
+ /// The type parameters can be any document class, scalar or JSON-serializable class.
+ /// For each result type parameter, the SQL SELECT statement must contain a ROW.
+ /// For document types, the row must contain the required fields in the correct order,
+ /// depending on the session type and the metadata the document might use, at least id and data must be
+ /// provided.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// An async enumerable iterating over the list of result tuples
+ IAsyncEnumerable<(T1, T2, T3)> StreamAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
}
diff --git a/src/Marten/IDocumentOperations.cs b/src/Marten/IDocumentOperations.cs
index 68364f4f8b..cbac739cfe 100644
--- a/src/Marten/IDocumentOperations.cs
+++ b/src/Marten/IDocumentOperations.cs
@@ -232,6 +232,15 @@ public interface IDocumentOperations: IQuerySession
///
void QueueSqlCommand(string sql, params object[] parameterValues);
+ ///
+ /// Registers a SQL command to be executed with the underlying unit of work as part of the batched command.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ void QueueSqlCommand(char placeholder, string sql, params object[] parameterValues);
+
///
/// In the case of a lightweight session, this will direct Marten to opt into identity map mechanics
/// for only the document type T. This is a micro-optimization added for the event sourcing + projections
diff --git a/src/Marten/IQuerySession.cs b/src/Marten/IQuerySession.cs
index 9f11775fbc..c61288b0e2 100644
--- a/src/Marten/IQuerySession.cs
+++ b/src/Marten/IQuerySession.cs
@@ -184,6 +184,7 @@ public interface IQuerySession: IDisposable, IAsyncDisposable
///
///
///
+ [Obsolete(QuerySession.SynchronousRemoval)]
IReadOnlyList Query(string sql, params object[] parameters);
///
@@ -197,6 +198,19 @@ public interface IQuerySession: IDisposable, IAsyncDisposable
///
Task StreamJson(Stream destination, CancellationToken token, string sql, params object[] parameters);
+ ///
+ /// Stream the results of a user-supplied query directly to a stream as a JSON array.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task StreamJson(Stream destination, CancellationToken token, char placeholder, string sql, params object[] parameters);
+
///
/// Stream the results of a user-supplied query directly to a stream as a JSON array
///
@@ -207,6 +221,18 @@ public interface IQuerySession: IDisposable, IAsyncDisposable
///
Task StreamJson(Stream destination, string sql, params object[] parameters);
+ ///
+ /// Stream the results of a user-supplied query directly to a stream as a JSON array.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task StreamJson(Stream destination, char placeholder, string sql, params object[] parameters);
+
///
/// Asynchronously queries the document storage table for the document type T by supplied SQL. See
/// https://martendb.io/documents/querying/sql.html for more information on usage.
@@ -218,6 +244,19 @@ public interface IQuerySession: IDisposable, IAsyncDisposable
///
Task> QueryAsync(string sql, CancellationToken token, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage table for the document type T by supplied SQL. See
+ /// https://martendb.io/documents/querying/sql.html for more information on usage.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryAsync(char placeholder, string sql, CancellationToken token, params object[] parameters);
+
///
/// Asynchronously queries the document storage table for the document type T by supplied SQL. See
/// https://martendb.io/documents/querying/sql.html for more information on usage.
@@ -228,6 +267,18 @@ public interface IQuerySession: IDisposable, IAsyncDisposable
///
Task> QueryAsync(string sql, params object[] parameters);
+ ///
+ /// Asynchronously queries the document storage table for the document type T by supplied SQL. See
+ /// https://martendb.io/documents/querying/sql.html for more information on usage.
+ /// Use to specify a character that will be replaced by positional parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryAsync(char placeholder, string sql, params object[] parameters);
+
///
/// Asynchronously queries the document storage with the supplied SQL.
/// The type parameter can be a document class, a scalar or any JSON-serializable class.
diff --git a/src/Marten/Internal/Operations/ExecuteSqlStorageOperation.cs b/src/Marten/Internal/Operations/ExecuteSqlStorageOperation.cs
index b0f4502f03..3c114d92c5 100644
--- a/src/Marten/Internal/Operations/ExecuteSqlStorageOperation.cs
+++ b/src/Marten/Internal/Operations/ExecuteSqlStorageOperation.cs
@@ -12,17 +12,19 @@ namespace Marten.Internal.Operations;
internal class ExecuteSqlStorageOperation: IStorageOperation, NoDataReturnedCall
{
private readonly string _commandText;
+ private readonly char _placeholder;
private readonly object[] _parameterValues;
- public ExecuteSqlStorageOperation(string commandText, params object[] parameterValues)
+ public ExecuteSqlStorageOperation(char placeholder, string commandText, params object[] parameterValues)
{
_commandText = commandText.TrimEnd(';');
+ _placeholder = placeholder;
_parameterValues = parameterValues;
}
public void ConfigureCommand(ICommandBuilder builder, IMartenSession session)
{
- var parameters = builder.AppendWithParameters(_commandText);
+ var parameters = builder.AppendWithParameters(_commandText, _placeholder);
if (parameters.Length != _parameterValues.Length)
{
throw new InvalidOperationException(
diff --git a/src/Marten/Internal/Sessions/DocumentSessionBase.cs b/src/Marten/Internal/Sessions/DocumentSessionBase.cs
index 597ffdbd6a..fdbad417b7 100644
--- a/src/Marten/Internal/Sessions/DocumentSessionBase.cs
+++ b/src/Marten/Internal/Sessions/DocumentSessionBase.cs
@@ -226,13 +226,18 @@ public void InsertObjects(IEnumerable