doParseSQL method

String doParseSQL(
  1. String sql,
  2. TSQLParseOptions options,
  3. TParamStyle parameterStyle,
  4. TParamBinding paramBinding,
  5. String macroChar,
  6. TStringRef replaceString,
)

Implementation

String doParseSQL(
    String sql,
    TSQLParseOptions options,
    TParamStyle parameterStyle,
    TParamBinding paramBinding,
    String macroChar,
    TStringRef replaceString) {
  if (options.contains(TSQLParseOption.spoCreate)) clear();

  // Parse the SQL and build ParamBinding (original comment kept as-is)
  final escapeSlash = options.contains(TSQLParseOption.spoEscapeSlash);
  final escapeRepeat = options.contains(TSQLParseOption.spoEscapeRepeat);
  var paramCount = 0;
  final paramPartStart = <int>[];
  final paramPartStop = <int>[];
  paramBinding.clear();
  var questionMarkParamCount = 0; // number of ? params found in query

  replaceString.value = r'$';
  if (parameterStyle == TParamStyle.psSimulated) {
    while (sql.contains(replaceString.value)) {
      replaceString.value = '${replaceString.value}\$';
    }
  }

  final p = TIntRef(0);
  // ParamDelim
  final Set<String> paramDelim = options.contains(TSQLParseOption.spoUseMacro)
      ? {macroChar}
      : {':', "?"};

  // characters that may not appear in a parameter name (SQLDelimiterCharacters + extra symbols)
  const extraDelims = {
    '=',
    "+",
    "-",
    "*",
    "\\",
    "/",
    "[",
    "]",
    "|",
    "<",
    ">"
  };

  while (true) {
    while (skipComments(sql, p, escapeSlash, escapeRepeat)) {}
    if (p.value < sql.length && paramDelim.contains(sql[p.value])) {
      // parameter
      var ignorePart = false;
      int paramNameStart;
      String paramName;
      if (sql[p.value] != '?') {
        // find parameter name
        p.value++;
        if (p.value < sql.length &&
            (sql[p.value] == ':' ||
                sql[p.value] == '=' ||
                sql[p.value] == ' ')) {
          // ignore ::, since some databases (postgres) uses this as a
          // cast (wb 4813) (original comment kept as-is)
          ignorePart = true;
          p.value++;
          paramNameStart = p.value;
          paramName = '';
        } else if (p.value < sql.length && sql[p.value] == '"') {
          // Check if the parameter-name is between quotes
          paramNameStart = p.value;
          skipQuotesString(sql, p, '"', escapeSlash, escapeRepeat);
          // Do not include the quotes in ParamName, but they must be
          // included when the parameter is replaced by some
          // place-holder. (original comment kept as-is)
          paramName = sql.substring(paramNameStart + 1, p.value - 1);
        } else {
          paramNameStart = p.value;
          while (p.value < sql.length &&
              !sqlDelimiterCharacters.contains(sql[p.value]) &&
              !extraDelims.contains(sql[p.value])) {
            p.value++;
          }
          paramName = sql.substring(paramNameStart, p.value);
        }
      } else {
        p.value++;
        paramNameStart = p.value;
        paramName = '';
      }

      if (!ignorePart) {
        paramCount++;
        int parameterIndex;
        if (options.contains(TSQLParseOption.spoCreate)) {
          // Check if this is the first occurance of the parameter.
          // If so, create the parameter and assign the Parameterindex
          final tmpParam = findParam(paramName);
          if (tmpParam == null) {
            parameterIndex = createParam(
                    TFieldType.ftUnknown, paramName, TParamType.ptInput)
                .index;
          } else {
            // else only assign the ParameterIndex
            parameterIndex = tmpParam.index;
          }
        } else {
          // else find ParameterIndex
          if (paramName != '') {
            parameterIndex = paramByName(paramName).index;
          } else {
            parameterIndex = questionMarkParamCount;
            questionMarkParamCount++;
          }
        }

        // store ParameterIndex, ParamPart data
        // ParamPart.Start includes the leading ':' or '?' character (1-based→0-based)
        paramBinding.add(parameterIndex);
        paramPartStart.add(paramNameStart > 0 ? paramNameStart - 1 : 0);
        paramPartStop.add(p.value);
      }
    } else if (p.value >= sql.length) {
      break; // end of SQL
    } else {
      p.value++;
    }
  }

  if (paramCount > 0) {
    // replace :ParamName by ? for interbase and by $x for
    // postgresql/psSimulated (original comment kept as-is)
    final newQuery = StringBuffer();
    var bufIndex = 0;
    for (var i = 0; i < paramPartStart.length; i++) {
      newQuery.write(sql.substring(bufIndex, paramPartStart[i]));
      switch (parameterStyle) {
        case TParamStyle.psInterbase:
          newQuery.write("?");
          break;
        case TParamStyle.psPostgreSQL:
        case TParamStyle.psSimulated:
          newQuery.write(replaceString.value);
          newQuery.write("${paramBinding[i] + 1}");
          break;
      }
      bufIndex = paramPartStop[i];
    }
    if (bufIndex < sql.length) {
      newQuery.write(sql.substring(bufIndex));
    }
    return newQuery.toString();
  }
  return sql;
}