content: package com.alibaba.druid.bvt.sql.postgresql.issues;
  
  import com.alibaba.druid.DbType;
  import com.alibaba.druid.sql.SQLUtils;
  import com.alibaba.druid.sql.ast.SQLStatement;
  import com.alibaba.druid.sql.parser.SQLParserUtils;
  import com.alibaba.druid.sql.parser.SQLStatementParser;
  import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
  import com.alibaba.druid.stat.TableStat;
  import org.apache.commons.lang3.StringUtils;
  import org.junit.Test;
  
  import java.util.Map;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertTrue;
  
  /**
   * 验证 Postgresql 无法解析 create table PARTITION OF 语句 #5366
   *
   * @author lizongbo
   * @see <a href="https://github.com/alibaba/druid/issues/5366">增强 #5366</a>
   * @see <a href="https://www.postgresql.org/docs/current/sql-createtable.html">CREATE TABLE</a>
   */
  public class Issue5366 {
      @Test
      public void test_create_table() throws Exception {
          for (DbType dbType : new DbType[]{DbType.postgresql}) {
              for (String sql : new String[]{
                  "CREATE TABLE orders_p4 PARTITION OF orders\n"
                      + "    FOR VALUES WITH (MODULUS 4, REMAINDER 3);",
                  "CREATE TABLE measurement_y2016m07\n"
                      + "    PARTITION OF measurement (\n"
                      + "    unitsales DEFAULT 0\n"
                      + ") FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');",
                  "CREATE TABLE cities_ab\n"
                      + "    PARTITION OF cities (\n"
                      + "    CONSTRAINT city_id_nonzero CHECK (city_id != 0)\n"
                      + ") FOR VALUES IN ('a', 'b');",
                  "CREATE TABLE measurement_ym_y2017m01\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES IN (2017, 1) PARTITION BY RANGE (population);",
                  "CREATE TABLE IF NOT EXISTS lc_event_1689811200000 PARTITION OF lc_event FOR VALUES FROM (1689811200000) TO (1690416000000);",
                  "CREATE TABLE measurement_ym_older\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES FROM (MINVALUE, MINVALUE) TO (2016, 11);",
                  "CREATE TABLE measurement_ym_y2016m11\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES FROM (2016, 11) TO (2016, 12);",
                  "CREATE TABLE measurement_ym_y2016m12\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES FROM (2016, 12) TO (2017, 1);",
                  "CREATE TABLE measurement_ym_y2017m01\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES FROM (2017, 1) TO (2017, 2);",
                  "CREATE TABLE measurement_ym_y2017m02\n"
                      + "    PARTITION OF measurement_year_month\n"
                      + "    FOR VALUES IN (2017, 1) PARTITION BY RANGE (population);",
                  "CREATE TABLE cities_ab\n"
                      + "    PARTITION OF cities (\n"
                      + "    CONSTRAINT city_id_nonzero CHECK (city_id != 0)\n"
                      + ") FOR VALUES IN ('a', 'b') PARTITION BY RANGE (population);",
                  "CREATE TABLE cities_ab_10000_to_100000\n"
                      + "    PARTITION OF cities_ab FOR VALUES FROM (10000) TO (100000);",
                  "CREATE TABLE orders_p1 PARTITION OF orders\n"
                      + "    FOR VALUES WITH (MODULUS 4, REMAINDER 0);",
                  "CREATE TABLE orders_p2 PARTITION OF orders\n"
                      + "    FOR VALUES WITH (MODULUS 4, REMAINDER 1);",
                  "CREATE TABLE orders_p3 PARTITION OF orders\n"
                      + "    FOR VALUES WITH (MODULUS 4, REMAINDER 2);",
                  "CREATE TABLE cities_partdef\n"
                      + "    PARTITION OF cities DEFAULT;",
              }) {
                  System.out.println(dbType + "原始的sql===" + sql);
                  String normalizeSql = normalizeSql(sql);
                  SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
                  SQLStatement statement = parser.parseStatement();
                  System.out.println(dbType + "生成的sql===" + statement);
                  String newSql = statement.toString();
                  String normalizeNewSql = normalizeSql(newSql);
                  assertEquals(normalizeSql.toLowerCase(), normalizeNewSql.toLowerCase());
                  SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
                  statement.accept(visitor);
                  System.out.println(dbType + "getTables==" + visitor.getTables());
                  Map<TableStat.Name, TableStat> tableMap = visitor.getTables();
                  assertTrue(!tableMap.isEmpty());
              }
  
          }
      }
      static String normalizeSql(String sql) {
          sql = StringUtils.replace(sql, " ( ", "(");
          sql = StringUtils.replace(sql, "( ", "(");
          sql = StringUtils.replace(sql, " )", ")");
          sql = StringUtils.replace(sql, "\t", " ");
          sql = StringUtils.replace(sql, "\n", " ");
          sql = StringUtils.replace(sql, "\'", "\"");
          sql = StringUtils.replace(sql, " ( ", "(");
          sql = StringUtils.replace(sql, " (", "(");
          sql = StringUtils.replace(sql, "( ", "(");
          sql = StringUtils.replace(sql, " )", ")");
          sql = StringUtils.replace(sql, "( ", "(");
          sql = StringUtils.replace(sql, "  ", " ");
          sql = StringUtils.replace(sql, "  ", " ");
          sql = StringUtils.replace(sql, "  ", " ");
          sql = StringUtils.replace(sql, "  ", " ");
          sql = StringUtils.replace(sql, "( ", "(");
          sql = StringUtils.replace(sql, ", ", ",");
          sql = StringUtils.replace(sql, " ,", ",");
          return sql;
      }
  }
  