/// <summary>
        /// Converts the value of a specified object to an equivalent string representation using specified format and culture-specific formatting information.
        /// </summary>
        /// <param name="format">A format string containing formatting specifications.</param>
        /// <param name="arg">An object to format.</param>
        /// <param name="formatProvider">An object that supplies format information about the current instance.</param>
        /// <returns>
        /// The string representation of the value of <paramref name="arg" />, formatted as specified by <paramref name="format" /> and <paramref name="formatProvider" />.
        /// </returns>
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            // Check whether this is an appropriate callback
            if (!this.Equals(formatProvider))
            {
                return(null);
            }
            if (arg == null)
            {
                return(null);
            }

            var    parts = (format ?? "").Split(':');
            var    sql   = new SqlFormatter();
            string formatString;

            switch (parts[0])
            {
            case "aml":
                formatString = string.Join(":", parts, 1, parts.Length - 1);
                return(Format(arg,
                              n => n.ToString(format, CultureInfo.InvariantCulture),
                              o => GetString(o, formatString)));

            case "sql":
                formatString = string.Join(":", parts, 1, parts.Length - 1);
                return(XmlEscape(sql.Format(formatString, arg, sql)));

            case "rawsql":
                formatString = string.Join(":", parts, 1, parts.Length - 1);
                return(sql.Format(formatString, arg, sql));

            default:
                formatString = format;
                return(Format(arg,
                              n => n.ToString(format, CultureInfo.InvariantCulture),
                              o => XmlEscape(GetString(o, formatString))));
            }
        }
    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
      // Check whether this is an appropriate callback              
      if (!this.Equals(formatProvider)) return null;
      if (arg == null) return null;

      var parts = (format ?? "").Split(':');
      var sql = new SqlFormatter(this);
      string formatString;

      switch (parts[0])
      {
        case "aml":
          formatString = string.Join(":", parts, 1, parts.Length - 1);
          return Format(arg,
            n => n.ToString(format, CultureInfo.InvariantCulture),
            o => GetString(o, formatString));
        case "sql":
          formatString = string.Join(":", parts, 1, parts.Length - 1);
          return XmlEscape(sql.Format(formatString, arg, sql));
        case "rawsql":
          formatString = string.Join(":", parts, 1, parts.Length - 1);
          return sql.Format(formatString, arg, sql);
        default:
          formatString = format;
          return Format(arg,
            n => n.ToString(format, CultureInfo.InvariantCulture),
            o => XmlEscape(GetString(o, formatString)));
      }
    }
        internal static string RenderSqlEnum(object value, bool quoteStrings, Func <IFormattable, string> numberRenderer, Func <object, string> stringRenderer, Func <string> emptyEnumRenderer)
        {
            if (value is string)
            {
                return(stringRenderer(value));
            }

            var first   = true;
            var builder = new StringBuilder();

            if (TryGetNumericEnumerable(value, out var enumerable))
            {
                foreach (var item in enumerable)
                {
                    if (!first)
                    {
                        builder.Append(",");
                    }
                    builder.Append(numberRenderer((IFormattable)item));
                    first = false;
                }

                if (first)
                {
                    return(emptyEnumRenderer?.Invoke());
                }
            }
            else
            {
                enumerable = value as IEnumerable;
                if (enumerable != null)
                {
                    foreach (var item in enumerable)
                    {
                        if (!first)
                        {
                            builder.Append(",");
                        }
                        if (quoteStrings)
                        {
                            builder.Append(SqlFormatter.Quote(stringRenderer(item).Replace("'", "''")));
                        }
                        else
                        {
                            builder.Append(stringRenderer(item));
                        }
                        first = false;
                    }

                    // Nothing was written as there were not values in the IEnumerable
                    // Therefore, write a bogus value to match zero results
                    if (first)
                    {
                        var empty = emptyEnumRenderer?.Invoke();
                        if (empty == null)
                        {
                            return(null);
                        }
                        return(quoteStrings
              ? "N'" + emptyEnumRenderer?.Invoke() + "'"
              : emptyEnumRenderer?.Invoke());
                    }
                }
                else
                {
                    return(stringRenderer(value));
                }
            }

            return(builder.ToString());
        }
 private string SqlReplace(string query)
 {
   var builder = new StringBuilder(query.Length);
   var formatter = new SqlFormatter(_context);
   SqlReplace(query, '@', builder, p =>
   {
     object value;
     if (TryGetParamValue(p, out value))
     {
       IFormattable num;
       if (ServerContext.TryCastNumber(value, out num))
       {
         return formatter.Format(num);
       }
       else if (builder.ToString().EndsWith(" in ") && value is IEnumerable)
       {
         return "(" + RenderSqlEnum(value, true, o => formatter.Format(o)) + ")";
       }
       else
       {
         return "N'" + RenderSqlEnum(value, false, o => formatter.Format(o)) + "'";
       }
     }
     else
     {
       return "@" + p;
     }
   });
   return builder.ToString();
 }