Hi all,
I try to use validation with multi-statement AST but it fails when I call
validate() with NPE about namespace, I wonder how should I set this namespace:
NlsString ';'
BigDecimal 1
Exception in thread "main" java.lang.NullPointerException: namespace for SELECT
';', scope org.apache.calcite.sql.validate.CatalogScope@2f7a7219
at java.base/java.util.Objects.requireNonNull(Objects.java:334)
at
org.apache.calcite.sql.validate.SqlValidatorImpl.getNamespaceOrThrow(SqlValidatorImpl.java:1273)
at
org.apache.calcite.sql.validate.SqlValidatorImpl.validateQuery(SqlValidatorImpl.java:1058)
at org.apache.calcite.sql.SqlSelect.validate(SqlSelect.java:247)
at org.apache.calcite.sql.SqlNodeList.validate(SqlNodeList.java:261)
at
org.apache.calcite.sql.validate.SqlValidatorImpl.validateScopedExpression(SqlValidatorImpl.java:1046)
at
org.apache.calcite.sql.validate.SqlValidatorImpl.validate(SqlValidatorImpl.java:752)
at
org.example.CalciteMultiStatementValidationExample2.main(CalciteMultiStatementValidationExample.java:116)
The example source code:
public class CalciteMultiStatementValidationExample
{
public static void main( String[] args )
throws SQLException, SqlParseException, ValidationException,
RelConversionException, IOException,
ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException,
IllegalAccessException
{
SqlParser.Config parserConfig = SqlParser
.config()
.withConformance(SqlConformanceEnum.BABEL)
.withParserFactory(SqlDdlParserImpl.FACTORY);
SqlNodeList list = SqlParser.create(new SourceStringReader("select ';'
; select 1"), parserConfig).parseStmtList();
for (SqlNode stmt : list.stream().toList()) {
for (SqlNode sqlNode1 : ((SqlSelect)stmt).getSelectList()) {
SqlLiteral sqlNode11 = (SqlLiteral) sqlNode1;
System.out.println(sqlNode11.getValue().getClass().getSimpleName() + " " +
sqlNode11.getValue());
}
}
RelDataTypeSystem DEFAULT = new RelDataTypeSystemImpl() { };
JavaTypeFactoryImpl javaTypeFactory = new JavaTypeFactoryImpl(DEFAULT);
Connection connection = DriverManager.getConnection("jdbc:calcite:");
CalciteConnection calciteConnection =
connection.unwrap(CalciteConnection.class);
SchemaPlus rootSchema = calciteConnection.getRootSchema();
final DataSource ds = JdbcSchema.dataSource(
"jdbc:hsqldb:mem:db",
"org.hsqldb.jdbc.JDBCDriver",
"SA",
"");
JdbcSchema schema = JdbcSchema.create(rootSchema, "main", ds, null,
"INFORMATION_SCHEMA");
rootSchema.add("main", schema);
Properties properties = new Properties();
properties.setProperty(CalciteConnectionProperty.CASE_SENSITIVE.camelName(),
String.valueOf(false));
properties.setProperty(CalciteConnectionProperty.CONFORMANCE.camelName(),
SqlConformanceEnum.LENIENT.name());
CalciteConnectionConfigImpl cc = new
CalciteConnectionConfigImpl(properties);
CalciteCatalogReader cr = new CalciteCatalogReader(
CalciteSchema.from(rootSchema),
Collections.singletonList("main"),
javaTypeFactory,
cc
);
class CalciteSqlValidator extends SqlValidatorImpl
{
CalciteSqlValidator(SqlOperatorTable opTab,
CalciteCatalogReader catalogReader,
JavaTypeFactory typeFactory,
Config config) {
super(opTab, catalogReader, typeFactory, config);
}
@Override protected RelDataType getLogicalSourceRowType(
RelDataType sourceRowType, SqlInsert insert) {
final RelDataType superType =
super.getLogicalSourceRowType(sourceRowType, insert);
return ((JavaTypeFactory) typeFactory).toSql(superType);
}
@Override protected RelDataType getLogicalTargetRowType(
RelDataType targetRowType, SqlInsert insert) {
final RelDataType superType =
super.getLogicalTargetRowType(targetRowType, insert);
return ((JavaTypeFactory) typeFactory).toSql(superType);
}
}
SqlOperatorTable chain =
SqlOperatorTables.chain(SqlStdOperatorTable.instance(), cr);
SqlValidator.Config config = SqlValidator.Config.DEFAULT
.withConformance(SqlConformanceEnum.BABEL)
.withDefaultNullCollation(cc.defaultNullCollation())
.withLenientOperatorLookup(cc.lenientOperatorLookup())
.withConformance(cc.conformance())
.withIdentifierExpansion(true);
SqlNode validate = new CalciteSqlValidator(chain, cr, javaTypeFactory,
config).validate(list);
System.out.println(validate.toString());
}
}