static Statement replaceForUpdate()

in src/main/java/com/google/cloud/spanner/pgadapter/statements/SimpleParser.java [243:291]


  static Statement replaceForUpdate(
      Statement statement, String lowerCaseSql, boolean replaceWithHint) {
    // If there is no 'for' clause, then we know that we don't have to analyze any further.
    if (!lowerCaseSql.contains("for")) {
      return statement;
    }
    SimpleParser parser = new SimpleParser(statement.getSql());
    parser.parseExpressionUntilKeyword(ImmutableList.of("for"), true, false, false);
    if (parser.pos >= parser.getSql().length()) {
      return statement;
    }
    int startPos = parser.pos;
    if (parser.eatKeyword("for") && parser.eatKeyword("update")) {
      if (!replaceWithHint) {
        startPos = parser.pos;
      }
      int endPos = parser.pos;
      // Skip 'of table1[, table2[, ...]] clauses
      if (parser.eatKeyword("of")) {
        List<TableOrIndexName> tables = parser.readTableList();
        if (tables.isEmpty()) {
          return statement;
        }
        endPos = parser.pos;
      } else if (!replaceWithHint) {
        // Stop here if the statement does not contain an 'of table' clause.
        return statement;
      }
      // 'nowait' and 'skip locked' clauses are not supported.
      if (parser.eatKeyword("nowait") || parser.eatKeyword("skip")) {
        return statement;
      }
      if (parser.hasMoreTokens()) {
        return statement;
      }
      // This is a simple 'for update' clause. Replace it with a 'LOCK_SCANNED_RANGES=exclusive'
      // hint and/or remove the 'of table' clause.
      if (replaceWithHint) {
        return Statement.of(
            "/*@ LOCK_SCANNED_RANGES=exclusive */"
                + statement.getSql().substring(0, startPos)
                + statement.getSql().substring(endPos));
      } else {
        return Statement.of(
            statement.getSql().substring(0, startPos) + statement.getSql().substring(endPos));
      }
    }
    return statement;
  }