Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a26f980

Browse files
committedMay 12, 2024·
Escapes string in AbstractStringType
1 parent b967119 commit a26f980

13 files changed

+154
-12
lines changed
 

‎src/NHibernate/Cfg/Environment.cs

+6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ public static string Version
119119
/// <summary> Enable formatting of SQL logged to the console</summary>
120120
public const string FormatSql = "format_sql";
121121

122+
/// <summary>
123+
/// Indicates if the database needs to have backslash escaped in string literals.
124+
/// </summary>
125+
/// <remarks>The default value is dialect dependent.</remarks>
126+
public const string EscapeBackslashInStrings = "escape_backslash_in_strings";
127+
122128
// Since v5.0.1
123129
[Obsolete("This setting has no usages and will be removed in a future version")]
124130
public const string UseGetGeneratedKeys = "jdbc.use_get_generated_keys";

‎src/NHibernate/Dialect/DB2Dialect.cs

+25
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using NHibernate.Dialect.Function;
66
using NHibernate.Dialect.Schema;
77
using NHibernate.SqlCommand;
8+
using NHibernate.SqlTypes;
89

910
namespace NHibernate.Dialect
1011
{
@@ -296,6 +297,30 @@ public override string ForUpdateString
296297

297298
public override long TimestampResolutionInTicks => 10L; // Microseconds.
298299

300+
/// <inheritdoc />
301+
public override string ToStringLiteral(string value, SqlType type)
302+
{
303+
if (value == null)
304+
throw new System.ArgumentNullException(nameof(value));
305+
if (type == null)
306+
throw new System.ArgumentNullException(nameof(value));
307+
308+
// See https://www.ibm.com/docs/en/db2/11.5?topic=elements-constants#r0000731__title__7
309+
var literal = new StringBuilder(value);
310+
var isUnicode = type.DbType == DbType.String || type.DbType == DbType.StringFixedLength;
311+
if (isUnicode)
312+
literal.Replace(@"\", @"\\");
313+
314+
literal
315+
.Replace("'", "''")
316+
.Insert(0, '\'')
317+
.Append('\'');
318+
319+
if (isUnicode)
320+
literal.Insert(0, "U&");
321+
return literal.ToString();
322+
}
323+
299324
#region Overridden informational metadata
300325

301326
public override bool SupportsNullInUnique => false;

‎src/NHibernate/Dialect/Dialect.cs

+50-8
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ public virtual void Configure(IDictionary<string, string> settings)
208208
DefaultCastLength = PropertiesHelper.GetInt32(Environment.QueryDefaultCastLength, settings, 4000);
209209
DefaultCastPrecision = PropertiesHelper.GetByte(Environment.QueryDefaultCastPrecision, settings, null) ?? 29;
210210
DefaultCastScale = PropertiesHelper.GetByte(Environment.QueryDefaultCastScale, settings, null) ?? 10;
211+
EscapeBackslashInStrings = PropertiesHelper.GetBoolean(Environment.EscapeBackslashInStrings, settings, EscapeBackslashInStrings);
211212
}
212213

213214
#endregion
@@ -1354,14 +1355,6 @@ public virtual CaseFragment CreateCaseFragment()
13541355
return new ANSICaseFragment(this);
13551356
}
13561357

1357-
/// <summary> The SQL literal value to which this database maps boolean values. </summary>
1358-
/// <param name="value">The boolean value </param>
1359-
/// <returns> The appropriate SQL literal. </returns>
1360-
public virtual string ToBooleanValueString(bool value)
1361-
{
1362-
return value ? "1" : "0";
1363-
}
1364-
13651358
internal static void ExtractColumnOrAliasNames(SqlString select, out List<SqlString> columnsOrAliases, out Dictionary<SqlString, SqlString> aliasToColumn, out Dictionary<SqlString, SqlString> columnToAlias)
13661359
{
13671360
columnsOrAliases = new List<SqlString>();
@@ -2076,6 +2069,55 @@ public virtual string ConvertQuotesForCatalogName(string catalogName)
20762069

20772070
#endregion
20782071

2072+
#region Literals support
2073+
2074+
/// <summary>The SQL literal value to which this database maps boolean values.</summary>
2075+
/// <param name="value">The boolean value.</param>
2076+
/// <returns>The appropriate SQL literal.</returns>
2077+
public virtual string ToBooleanValueString(bool value)
2078+
=> value ? "1" : "0";
2079+
2080+
/// <summary>
2081+
/// <see langword="true" /> if the database needs to have backslash escaped in string literals.
2082+
/// </summary>
2083+
/// <remarks><see langword="false" /> by default in the base dialect, to conform to SQL standard.</remarks>
2084+
protected virtual bool EscapeBackslashInStrings { get; set; }
2085+
2086+
/// <summary>
2087+
/// <see langword="true" /> if the database needs to have Unicode literals prefixed by <c>N</c>.
2088+
/// </summary>
2089+
/// <remarks><see langword="false" /> by default in the base dialect.</remarks>
2090+
protected virtual bool UseNPrefixForUnicodeStrings { get; set; }
2091+
2092+
/// <summary>The SQL string literal value to which this database maps string values.</summary>
2093+
/// <param name="value">The string value.</param>
2094+
/// <param name="type">The SQL type of the string value.</param>
2095+
/// <returns>The appropriate SQL string literal.</returns>
2096+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> or
2097+
/// <paramref name="type"/> is <see langword="null" />.</exception>
2098+
public virtual string ToStringLiteral(string value, SqlType type)
2099+
{
2100+
if (value == null)
2101+
throw new ArgumentNullException(nameof(value));
2102+
if (type == null)
2103+
throw new ArgumentNullException(nameof(value));
2104+
2105+
var literal = new StringBuilder(value);
2106+
if (EscapeBackslashInStrings)
2107+
literal.Replace(@"\", @"\\");
2108+
2109+
literal
2110+
.Replace("'", "''")
2111+
.Insert(0, '\'')
2112+
.Append('\'');
2113+
2114+
if (UseNPrefixForUnicodeStrings && type.DbType == DbType.String || type.DbType == DbType.StringFixedLength)
2115+
literal.Insert(0, 'N');
2116+
return literal.ToString();
2117+
}
2118+
2119+
#endregion
2120+
20792121
#region Union subclass support
20802122

20812123
/// <summary>

‎src/NHibernate/Dialect/IngresDialect.cs

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public IngresDialect()
6262
/// <inheritdoc />
6363
public override int MaxAliasLength => 32;
6464

65+
/// <inheritdoc />
66+
/// <remarks><see langword="true" /> by default for Ingres,
67+
/// <see href="https://docs.actian.com/ingres/11.0/index.html#page/SQLRef/String_Literals.htm#ww110572" />.</remarks>
68+
protected override bool UseNPrefixForUnicodeStrings { get; set; } = true;
69+
6570
#region Overridden informational metadata
6671

6772
public override bool SupportsEmptyInList => false;

‎src/NHibernate/Dialect/MsSql2000Dialect.cs

+4
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,10 @@ public override bool SupportsSqlBatches
755755
/// </summary>
756756
public override int? MaxNumberOfParameters => 2097;
757757

758+
/// <inheritdoc />
759+
/// <remarks><see langword="true" /> by default for SQL Server.</remarks>
760+
protected override bool UseNPrefixForUnicodeStrings { get; set; } = true;
761+
758762
#region Overridden informational metadata
759763

760764
public override bool SupportsEmptyInList => false;

‎src/NHibernate/Dialect/MySQLDialect.cs

+10
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,16 @@ public override long TimestampResolutionInTicks
530530
/// </remarks>
531531
public override bool SupportsConcurrentWritingConnectionsInSameTransaction => false;
532532

533+
/// <inheritdoc />
534+
/// <remarks><see langword="true" /> by default for MySQL,
535+
/// <see href="https://dev.mysql.com/doc/refman/8.0/en/string-literals.html" />.</remarks>
536+
protected override bool EscapeBackslashInStrings { get; set; } = true;
537+
538+
/// <inheritdoc />
539+
/// <remarks><see langword="true" /> by default for MySQL,
540+
/// <see href="https://dev.mysql.com/doc/refman/8.0/en/string-literals.html" />.</remarks>
541+
protected override bool UseNPrefixForUnicodeStrings { get; set; } = true;
542+
533543
#region Overridden informational metadata
534544

535545
public override bool SupportsEmptyInList => false;

‎src/NHibernate/Dialect/Oracle8iDialect.cs

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public override void Configure(IDictionary<string, string> settings)
102102

103103
// If changing the default value, keep it in sync with OracleDataClientDriverBase.Configure.
104104
UseNPrefixedTypesForUnicode = PropertiesHelper.GetBoolean(Environment.OracleUseNPrefixedTypesForUnicode, settings, false);
105+
UseNPrefixForUnicodeStrings = UseNPrefixedTypesForUnicode;
106+
105107
RegisterCharacterTypeMappings();
106108
RegisterFloatingPointTypeMappings();
107109
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace NHibernate.Dialect
2+
{
3+
/// <summary>
4+
/// An SQL dialect for PostgreSQL 9.1 and above.
5+
/// </summary>
6+
/// <remarks>
7+
/// PostgreSQL 9.1 disables backslash escape sequences by default.
8+
/// </remarks>
9+
public class PostgreSQL91Dialect : PostgreSQL83Dialect
10+
{
11+
/// <inheritdoc />
12+
/// <remarks><see langword="false" /> by default for PostgreSQL version 9.1,
13+
/// <see href="https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE" />.</remarks>
14+
protected override bool EscapeBackslashInStrings { get; set; } = false;
15+
}
16+
}

‎src/NHibernate/Dialect/PostgreSQLDialect.cs

+5
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ public override string CurrentTimestampSelectString
320320
get { return "SELECT CURRENT_TIMESTAMP"; }
321321
}
322322

323+
/// <inheritdoc />
324+
/// <remarks><see langword="true" /> by default for PostgreSQL up until version 9.1,
325+
/// <see href="https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE" />.</remarks>
326+
protected override bool EscapeBackslashInStrings { get; set; } = true;
327+
323328
#region Overridden informational metadata
324329

325330
public override bool SupportsEmptyInList => false;

‎src/NHibernate/Dialect/SybaseASA9Dialect.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace NHibernate.Dialect
1010
{
1111
/// <summary>
12-
/// An SQL dialect for Sybase Adaptive Server Anywhere 9.0
12+
/// An SQL dialect for Sybase Adaptive Server Anywhere 9.0. (Renamed SQL Anywhere from its version 10.)
1313
/// </summary>
1414
/// <remarks>
1515
/// <p>
@@ -188,5 +188,15 @@ private static int GetAfterSelectInsertPoint(SqlString sql)
188188
}
189189
return 0;
190190
}
191+
192+
/// <inheritdoc />
193+
/// <remarks><see langword="true" /> by default for SQL Anywhere,
194+
/// <see href="https://help.sap.com/docs/SAP_SQL_Anywhere/93079d4ba8e44920ae63ffb4def91f5b/817a3ded6ce21014bd99f3e554573180.html?version=17.0" />.</remarks>
195+
protected override bool EscapeBackslashInStrings { get; set; } = true;
196+
197+
/// <inheritdoc />
198+
/// <remarks><see langword="true" /> by default for SQL Anywhere,
199+
/// <see href="https://help.sap.com/docs/SAP_SQL_Anywhere/93079d4ba8e44920ae63ffb4def91f5b/817a2c5f6ce21014aceea962de72126c.html?version=17.0" />.</remarks>
200+
protected override bool UseNPrefixForUnicodeStrings { get; set; } = true;
191201
}
192202
}

‎src/NHibernate/Dialect/SybaseSQLAnywhere10Dialect.cs

+10
Original file line numberDiff line numberDiff line change
@@ -969,5 +969,15 @@ public override IDataBaseSchema GetDataBaseSchema(DbConnection connection)
969969
/// <inheritdoc />
970970
/// <remarks>SQL Anywhere has a micro-second resolution.</remarks>
971971
public override long TimestampResolutionInTicks => 10L;
972+
973+
/// <inheritdoc />
974+
/// <remarks><see langword="true" /> by default for SQL Anywhere,
975+
/// <see href="https://help.sap.com/docs/SAP_SQL_Anywhere/93079d4ba8e44920ae63ffb4def91f5b/817a3ded6ce21014bd99f3e554573180.html?version=17.0" />.</remarks>
976+
protected override bool EscapeBackslashInStrings { get; set; } = true;
977+
978+
/// <inheritdoc />
979+
/// <remarks><see langword="true" /> by default for SQL Anywhere,
980+
/// <see href="https://help.sap.com/docs/SAP_SQL_Anywhere/93079d4ba8e44920ae63ffb4def91f5b/817a2c5f6ce21014aceea962de72126c.html?version=17.0" />.</remarks>
981+
protected override bool UseNPrefixForUnicodeStrings { get; set; } = true;
972982
}
973983
}

‎src/NHibernate/Type/AbstractStringType.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,9 @@ public object StringToObject(string xml)
134134

135135
#region ILiteralType Members
136136

137+
/// <inheritdoc />
137138
public string ObjectToSQLString(object value, Dialect.Dialect dialect)
138-
{
139-
return "'" + (string)value + "'";
140-
}
139+
=> dialect.ToStringLiteral((string)value, SqlType);
141140

142141
#endregion
143142

‎src/NHibernate/nhibernate-configuration.xsd

+8
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,14 @@
176176
<xs:enumeration value="default_flush_mode" />
177177
<xs:enumeration value="use_sql_comments" />
178178
<xs:enumeration value="format_sql" />
179+
<xs:enumeration value="escape_backslash_in_strings">
180+
<xs:annotation>
181+
<xs:documentation>
182+
Indicates if the database needs to have backslash escaped in string literals. The default is
183+
dialect dependent.
184+
</xs:documentation>
185+
</xs:annotation>
186+
</xs:enumeration>
179187
<xs:enumeration value="collectiontype.factory_class" />
180188
<xs:enumeration value="order_inserts" />
181189
<xs:enumeration value="order_updates" />

0 commit comments

Comments
 (0)
Please sign in to comment.