You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			146 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Data;
 | |
| using System.Data.Linq.Mapping;
 | |
| using System.Data.Linq.Provider;
 | |
| using System.Data.SqlClient;
 | |
| using System.Globalization;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Text.RegularExpressions;
 | |
| 
 | |
| namespace System.Data.Linq.SqlClient {
 | |
| 
 | |
|     internal static class SqlIdentifier
 | |
|     {
 | |
|         private static SqlCommandBuilder builder = new SqlCommandBuilder();
 | |
| 
 | |
|         const string ParameterPrefix = "@";
 | |
|         const string QuotePrefix = "[";
 | |
|         const string QuoteSuffix = "]";
 | |
|         const string SchemaSeparator = ".";
 | |
|         const char SchemaSeparatorChar = '.';
 | |
| 
 | |
|         private static bool IsQuoted(string s) {
 | |
|             if (s == null) {
 | |
|                 throw Error.ArgumentNull("s");
 | |
|             }
 | |
| 
 | |
|             if (s.Length < 2) {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             return s.StartsWith(QuotePrefix, StringComparison.Ordinal)
 | |
|                 && s.EndsWith(QuoteSuffix, StringComparison.Ordinal);
 | |
|         }
 | |
| 
 | |
|         // This is MSSQL-specific quoting.
 | |
|         // If the string begins and ends with [ and ], it will be assumed to already be quoted.
 | |
|         // Otherwise periods are assumed to be namespace delimiters, and the string is split on each.
 | |
|         // Each string from the split is then check to see if it is already quoted, and if
 | |
|         // not, it is replaced with the result of SqlCommandBuilder.QuoteIdentifier.
 | |
|         // Then the set of strings is rejoined with periods.
 | |
|         internal static string QuoteCompoundIdentifier(string s) {
 | |
|             if (s == null) {
 | |
|                 throw Error.ArgumentNull("s");
 | |
|             }
 | |
| 
 | |
|             // if it starts with @, then return unprocessed
 | |
|             if (s.StartsWith(ParameterPrefix, StringComparison.Ordinal)) {
 | |
|                 return s;
 | |
|             } else if (IsQuoted(s)) {
 | |
|                 return s;
 | |
|             }
 | |
|             else if (!s.StartsWith(QuotePrefix, StringComparison.Ordinal) && s.EndsWith(QuoteSuffix, StringComparison.Ordinal)) {
 | |
|                 //A.[B] => [A].[B]
 | |
|                 int splitPosition = s.IndexOf(SchemaSeparatorChar);
 | |
|                 if (splitPosition < 0){ //no . in the string
 | |
|                     return builder.QuoteIdentifier(s);
 | |
|                 }
 | |
|                 string left = s.Substring(0, splitPosition);
 | |
|                 string right = s.Substring(splitPosition + 1, s.Length - splitPosition - 1);
 | |
|                 if (!IsQuoted(right)) {
 | |
|                     right = builder.QuoteIdentifier(right);
 | |
|                 }
 | |
|                 return String.Concat(QuoteCompoundIdentifier(left), SchemaSeparatorChar + right);
 | |
|             }
 | |
|             else if (s.StartsWith(QuotePrefix, StringComparison.Ordinal) && !s.EndsWith(QuoteSuffix, StringComparison.Ordinal)) {
 | |
|                 //[A].B => [A].[B]
 | |
|                 int splitPosition = s.LastIndexOf(SchemaSeparatorChar);
 | |
|                 if (splitPosition < 0){ //no . in the string
 | |
|                     return builder.QuoteIdentifier(s);
 | |
|                 }
 | |
|                 string left = s.Substring(0, splitPosition);
 | |
|                 if (!IsQuoted(left)) {
 | |
|                     left = builder.QuoteIdentifier(left);
 | |
|                 }
 | |
|                 string right = s.Substring(splitPosition + 1, s.Length - splitPosition - 1);
 | |
|                 return String.Concat(left + SchemaSeparatorChar, QuoteCompoundIdentifier(right));
 | |
|             }
 | |
|             else {
 | |
|                 int splitPosition = s.IndexOf(SchemaSeparatorChar);
 | |
|                 if (splitPosition < 0) { //no . in the string
 | |
|                     //A => [A]
 | |
|                     return builder.QuoteIdentifier(s);
 | |
|                 }
 | |
|                 string left = s.Substring(0, splitPosition);
 | |
|                 string right = s.Substring(splitPosition + 1, s.Length - splitPosition - 1);
 | |
|                 return String.Concat(QuoteCompoundIdentifier(left) + SchemaSeparatorChar, QuoteCompoundIdentifier(right));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // This is MSSQL-specific quoting.
 | |
|         // This is the same as above, but it doesn't consider anything compound.
 | |
|         internal static string QuoteIdentifier(string s) {
 | |
|             if (s == null) {
 | |
|                 throw Error.ArgumentNull("s");
 | |
|             }
 | |
| 
 | |
|             // if it starts with @, then return unprocessed
 | |
|             if (s.StartsWith(ParameterPrefix, StringComparison.Ordinal)) {
 | |
|                 return s;
 | |
|             } else if (IsQuoted(s)) {
 | |
|                 return s;
 | |
|             } else {
 | |
|                 return builder.QuoteIdentifier(s);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // turns "[ABC].[PQR].[XYZ]" into {"[ABC]", "[PQR]", "[XYZ]"}
 | |
|         internal static IEnumerable<string> GetCompoundIdentifierParts(string s) {
 | |
|             if (s == null) {
 | |
|                 throw Error.ArgumentNull("s");
 | |
|             }
 | |
| 
 | |
|             // can't do this to parameters
 | |
|             if (s.StartsWith(ParameterPrefix, StringComparison.Ordinal)) {
 | |
|                 throw Error.ArgumentWrongValue("s");
 | |
|             }
 | |
| 
 | |
|             string quotedS = QuoteCompoundIdentifier(s);
 | |
|             string pattern = @"^(?<component>\[([^\]]|\]\])*\])(\.(?<component>\[([^\]]|\]\])*\]))*$";
 | |
| 
 | |
|             // This pattern matches "."-delimited quoted SQL identifiers. Here's how:
 | |
|             //
 | |
|             // 1. It is wrapped in "^" and "$", which match the begining and end of text, so it will match
 | |
|             //    only the entire text and not any sub-part.
 | |
|             // 2. The group "(?<component>\[([^\]]|\]\])*\])" captures a single quoted segment of the text.
 | |
|             //    It's a literal "[" followed by any number of non-"]" characters or "]]" strings, followed
 | |
|             //    by a literal "]". The "?<component>" bit names the capture so we can refer to it.
 | |
|             // 3. After the first component, we will allow any number of groups which consist of a literal
 | |
|             //    "." followed by a component (and the component part is a repeat of the part described in 2).
 | |
|  
 | |
|             Match m = Regex.Match(quotedS, pattern);
 | |
|             if (!m.Success)
 | |
|             {
 | |
|                 throw Error.ArgumentWrongValue("s");
 | |
|             }
 | |
| 
 | |
|             foreach (Capture cap in m.Groups["component"].Captures)
 | |
|             {
 | |
|                 yield return cap.Value;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |