Skip to content

Commit

Permalink
Better tests for providermode (now checks sql produced as well)
Browse files Browse the repository at this point in the history
Cleaned up sql server specific classes to make them generic and marked classes for #23
  • Loading branch information
FransBouma committed Apr 24, 2015
1 parent d3080a1 commit 27a17e3
Show file tree
Hide file tree
Showing 21 changed files with 466 additions and 407 deletions.
1 change: 0 additions & 1 deletion src/DbEngines/SqlServer/CommandTextProducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using SqlParameter = System.Data.SqlClient.SqlParameter;

namespace System.Data.Linq.DbEngines.SqlServer
{
Expand Down
6 changes: 3 additions & 3 deletions src/DbEngines/SqlServer/LongTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal override SqlSelect VisitSelect(SqlSelect select)
ConvertColumnsToMax(select, out changed, out containsLongExpressions);
if(containsLongExpressions)
{
this.annotations.Add(select, new SqlServerCompatibilityAnnotation(
this.annotations.Add(select, new CompatibilityAnnotation(
Strings.TextNTextAndImageCannotOccurInDistinct(select.SourceExpression), SqlServerProviderMode.Sql2000, SqlServerProviderMode.SqlCE));
}

Expand Down Expand Up @@ -118,7 +118,7 @@ internal override SqlNode VisitUnion(SqlUnion su)
{
// unless the UNION is 'ALL', the server will perform a DISTINCT operation,
// which isn't valid for large types (text, ntext, image)
this.annotations.Add(su, new SqlServerCompatibilityAnnotation(
this.annotations.Add(su, new CompatibilityAnnotation(
Strings.TextNTextAndImageCannotOccurInUnion(su.SourceExpression), SqlServerProviderMode.Sql2000, SqlServerProviderMode.SqlCE));
}
return base.VisitUnion(su);
Expand All @@ -132,7 +132,7 @@ internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc)
fc.Arguments[0] = ConvertToMax(fc.Arguments[0], out changed);
if(fc.Arguments[0].SqlType.IsLargeType)
{
this.annotations.Add(fc, new SqlServerCompatibilityAnnotation(
this.annotations.Add(fc, new CompatibilityAnnotation(
Strings.LenOfTextOrNTextNotSupported(fc.SourceExpression), SqlServerProviderMode.Sql2000));
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/DbEngines/SqlServer/SqlConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace System.Data.Linq.DbEngines.SqlServer
{
internal class SqlConnectionManager : ConnectionManager
{

#warning REFACTORING CANDIDATE FOR #23
#region Member Declarations
private SqlInfoMessageEventHandler infoMessagehandler;
#endregion
Expand Down
4 changes: 3 additions & 1 deletion src/DbEngines/SqlServer/SqlFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
namespace System.Data.Linq.DbEngines.SqlServer
{
/// <summary>
/// Class which produces SQL Server specific SQL fragments for SqlNode instances.
/// Class which produces SQL fragments for SqlNode instances.
/// </summary>
internal class SqlFormatter : DbFormatter
{
#warning REFACTOR. Introduce interface for CommandTextProducer to make it not tied to a specific DB.

#region Member Declarations
private CommandTextProducer _commandTextProducer;
#endregion
Expand Down
283 changes: 283 additions & 0 deletions src/DbEngines/SqlServer/SqlHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
using System.Text;

namespace System.Data.Linq.DbEngines.SqlServer
{
#warning [FB] BREAKING CHANGE. This namespace was in System.Data.Linq.SqlClient. Rename the new namespace or keep breaking change.

/// <summary>
/// Public helper methods to be used in queries.
/// </summary>
public static class SqlHelpers
{

public static string GetStringContainsPattern(string text, char escape)
{
bool usedEscapeChar = false;
return GetStringContainsPattern(text, escape, out usedEscapeChar);
}

internal static string GetStringContainsPattern(string text, char escape, out bool usedEscapeChar)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
return "%" + EscapeLikeText(text, escape, false, out usedEscapeChar) + "%";
}

internal static string GetStringContainsPatternForced(string text, char escape)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
bool usedEscapeChar = false;
return "%" + EscapeLikeText(text, escape, true, out usedEscapeChar) + "%";
}

public static string GetStringStartsWithPattern(string text, char escape)
{
bool usedEscapeChar = false;
return GetStringStartsWithPattern(text, escape, out usedEscapeChar);
}

internal static string GetStringStartsWithPattern(string text, char escape, out bool usedEscapeChar)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
return EscapeLikeText(text, escape, false, out usedEscapeChar) + "%";
}

internal static string GetStringStartsWithPatternForced(string text, char escape)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
bool usedEscapeChar = false;
return EscapeLikeText(text, escape, true, out usedEscapeChar) + "%";
}

public static string GetStringEndsWithPattern(string text, char escape)
{
bool usedEscapeChar = false;
return GetStringEndsWithPattern(text, escape, out usedEscapeChar);
}

internal static string GetStringEndsWithPattern(string text, char escape, out bool usedEscapeChar)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
return "%" + EscapeLikeText(text, escape, false, out usedEscapeChar);
}

internal static string GetStringEndsWithPatternForced(string text, char escape)
{
if(text == null)
{
throw Error.ArgumentNull("text");
}
bool usedEscapeChar = false;
return "%" + EscapeLikeText(text, escape, true, out usedEscapeChar);
}

private static string EscapeLikeText(string text, char escape, bool forceEscaping, out bool usedEscapeChar)
{
usedEscapeChar = false;
if(!(forceEscaping || text.Contains("%") || text.Contains("_") || text.Contains("[") || text.Contains("^")))
{
return text;
}
StringBuilder sb = new StringBuilder(text.Length);
foreach(char c in text)
{
if(c == '%' || c == '_' || c == '[' || c == '^' || c == escape)
{
sb.Append(escape);
usedEscapeChar = true;
}
sb.Append(c);
}
return sb.ToString();
}

public static string TranslateVBLikePattern(string pattern, char escape)
{
if(pattern == null)
{
throw Error.ArgumentNull("pattern");
}
const char vbMany = '*';
const char sqlMany = '%';
const char vbSingle = '?';
const char sqlSingle = '_';
const char vbDigit = '#';
const string sqlDigit = "[0-9]";
const char vbOpenBracket = '[';
const char sqlOpenBracket = '[';
const char vbCloseBracket = ']';
const char sqlCloseBracket = ']';
const char vbNotList = '!';
const char sqlNotList = '^';
const char vbCharRange = '-';
const char sqlCharRange = '-';

// walk the string, performing conversions
StringBuilder result = new StringBuilder();
bool bracketed = false;
bool charRange = false;
bool possibleNotList = false;
int numBracketedCharacters = 0;

foreach(char patternChar in pattern)
{
if(bracketed)
{
numBracketedCharacters++;

// if we're in a possible NotList, anything other than a close bracket will confirm it
if(possibleNotList)
{
if(patternChar != vbCloseBracket)
{
result.Append(sqlNotList);
possibleNotList = false;
}
else
{
result.Append(vbNotList);
possibleNotList = false;
}
}

switch(patternChar)
{
case vbNotList:
{
// translate to SQL's NotList only if the first character in the group
if(numBracketedCharacters == 1)
{
// latch this, and detect the next cycle
possibleNotList = true;
}
else
{
result.Append(patternChar);
}
break;
}
case vbCloseBracket:
{
// close down the bracket group
bracketed = false;
possibleNotList = false;
result.Append(sqlCloseBracket);
break;
}
case vbCharRange:
{
if(charRange)
{
// we've seen the char range indicator already -- SQL
// doesn't support multiple ranges in the same group
throw Error.VbLikeDoesNotSupportMultipleCharacterRanges();
}
else
{
// remember that we've seen this in the group
charRange = true;
result.Append(sqlCharRange);
break;
}
}
case sqlNotList:
{
if(numBracketedCharacters == 1)
{
// need to escape this one
result.Append(escape);
}
result.Append(patternChar);
break;
}
default:
{
if(patternChar == escape)
{
result.Append(escape);
result.Append(escape);
}
else
{
result.Append(patternChar);
}
break;
}
}
}
else
{
switch(patternChar)
{
case vbMany:
{
result.Append(sqlMany);
break;
}
case vbSingle:
{
result.Append(sqlSingle);
break;
}
case vbDigit:
{
result.Append(sqlDigit);
break;
}
case vbOpenBracket:
{
// we're openning a bracketed group, so reset the group state
bracketed = true;
charRange = false;
numBracketedCharacters = 0;
result.Append(sqlOpenBracket);
break;
}
// SQL's special characters need to be escaped
case sqlMany:
case sqlSingle:
{
result.Append(escape);
result.Append(patternChar);
break;
}
default:
{
if(patternChar == escape)
{
result.Append(escape);
result.Append(escape);
}
else
{
result.Append(patternChar);
}
break;
}
}
}
}

if(bracketed)
{
throw Error.VbLikeUnclosedBracket();
}

return result.ToString();
}
}
}
Loading

0 comments on commit 27a17e3

Please sign in to comment.