This is an automated email from the ASF dual-hosted git repository.

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e98700  [CALCITE-3900] Add Config for SqlValidator
4e98700 is described below

commit 4e9870078fcaa7da9e475c94f43309cc3244fa22
Author: yuzhao.cyz <[email protected]>
AuthorDate: Thu Apr 9 10:56:51 2020 +0800

    [CALCITE-3900] Add Config for SqlValidator
    
    The SqlValidator now has 7 setXXX methods for all kinds of control flags,
    which is hard for code evolving.
    
    There is also no way to config these things through the FrameworkConfig.
    
    Add a SqlValidator.Config to solve these problems.
---
 .../apache/calcite/jdbc/CalciteConnectionImpl.java |   4 +-
 .../apache/calcite/prepare/CalcitePrepareImpl.java |  11 +-
 .../calcite/prepare/CalciteSqlValidator.java       |   5 +-
 .../org/apache/calcite/prepare/PlannerImpl.java    |  27 ++-
 .../org/apache/calcite/sql/SqlCallBinding.java     |   8 +
 .../java/org/apache/calcite/sql/SqlFunction.java   |   4 +-
 .../java/org/apache/calcite/sql/SqlOperator.java   |   4 +-
 .../java/org/apache/calcite/sql/SqlWindow.java     |   8 +-
 .../calcite/sql/advise/SqlAdvisorValidator.java    |   7 +-
 .../apache/calcite/sql/fun/SqlCaseOperator.java    |   4 +-
 .../org/apache/calcite/sql/fun/SqlInOperator.java  |   4 +-
 .../sql/type/ComparableOperandTypeChecker.java     |   2 +-
 .../sql/type/CompositeOperandTypeChecker.java      |   6 +-
 .../calcite/sql/type/FamilyOperandTypeChecker.java |   4 +-
 .../SameOperandTypeExceptLastOperandChecker.java   |   2 +-
 .../calcite/sql/type/SetopOperandTypeChecker.java  |   2 +-
 .../calcite/sql/validate/IdentifierNamespace.java  |   2 +-
 .../apache/calcite/sql/validate/OrderByScope.java  |   2 +-
 .../apache/calcite/sql/validate/SqlValidator.java  | 183 ++++++++++++++++++++-
 .../calcite/sql/validate/SqlValidatorImpl.java     | 128 +++++++-------
 .../calcite/sql/validate/SqlValidatorUtil.java     |   8 +-
 .../apache/calcite/sql2rel/SqlToRelConverter.java  |  10 +-
 .../org/apache/calcite/tools/FrameworkConfig.java  |   6 +
 .../java/org/apache/calcite/tools/Frameworks.java  |  18 +-
 .../org/apache/calcite/util/ImmutableBeans.java    |   9 +-
 .../rel/logical/ToLogicalConverterTest.java        |   2 -
 .../apache/calcite/sql/test/SqlAdvisorTest.java    |   4 +-
 .../apache/calcite/sql/test/SqlTestFactory.java    |  10 +-
 .../java/org/apache/calcite/test/SqlTestGen.java   |   2 +-
 .../org/apache/calcite/test/SqlToRelTestBase.java  |  29 ++--
 .../calcite/test/SqlValidatorFeatureTest.java      |   5 +-
 .../org/apache/calcite/test/SqlValidatorTest.java  |   4 +-
 .../apache/calcite/test/SqlValidatorTestCase.java  |  18 +-
 33 files changed, 372 insertions(+), 170 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java 
b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
index a274793..48b1d36 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -58,7 +58,7 @@ import org.apache.calcite.sql.advise.SqlAdvisor;
 import org.apache.calcite.sql.advise.SqlAdvisorValidator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
-import org.apache.calcite.sql.validate.SqlConformanceEnum;
+import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorWithHints;
 import org.apache.calcite.tools.RelRunner;
 import org.apache.calcite.util.BuiltInMethod;
@@ -472,7 +472,7 @@ abstract class CalciteConnectionImpl
           new SqlAdvisorValidator(SqlStdOperatorTable.instance(),
               new CalciteCatalogReader(rootSchema,
                   schemaPath, typeFactory, con.config()),
-              typeFactory, SqlConformanceEnum.DEFAULT);
+              typeFactory, SqlValidator.Config.DEFAULT);
       final CalciteConnectionConfig config = con.config();
       // This duplicates 
org.apache.calcite.prepare.CalcitePrepareImpl.prepare2_
       final SqlParser.Config parserConfig = SqlParser.configBuilder()
diff --git 
a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java 
b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 3118958..b121f3a 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -628,8 +628,6 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
       final SqlValidator validator =
           createSqlValidator(context, catalogReader);
-      validator.setIdentifierExpansion(true);
-      validator.setDefaultNullCollation(config.defaultNullCollation());
 
       preparedResult = preparingStmt.prepareSql(
           sqlNode, Object.class, validator, true);
@@ -709,9 +707,14 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     final SqlOperatorTable opTab =
         ChainedSqlOperatorTable.of(opTab0, catalogReader);
     final JavaTypeFactory typeFactory = context.getTypeFactory();
-    final SqlConformance conformance = context.config().conformance();
+    final CalciteConnectionConfig connectionConfig = context.config();
+    final SqlValidator.Config config = SqlValidator.Config.DEFAULT
+        .withLenientOperatorLookup(connectionConfig.lenientOperatorLookup())
+        .withSqlConformance(connectionConfig.conformance())
+        .withDefaultNullCollation(connectionConfig.defaultNullCollation())
+        .withIdentifierExpansion(true);
     return new CalciteSqlValidator(opTab, catalogReader, typeFactory,
-        conformance);
+        config);
   }
 
   private List<ColumnMetaData> getColumnMetaDataList(
diff --git 
a/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java 
b/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
index 606323c..b8a5623 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteSqlValidator.java
@@ -20,7 +20,6 @@ import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlInsert;
 import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
 
 /** Validator. */
@@ -28,8 +27,8 @@ class CalciteSqlValidator extends SqlValidatorImpl {
 
   CalciteSqlValidator(SqlOperatorTable opTab,
       CalciteCatalogReader catalogReader, JavaTypeFactory typeFactory,
-      SqlConformance conformance) {
-    super(opTab, catalogReader, typeFactory, conformance);
+      Config config) {
+    super(opTab, catalogReader, typeFactory, config);
   }
 
   @Override protected RelDataType getLogicalSourceRowType(
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java 
b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index e76bb66..51a366b 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -48,7 +48,6 @@ import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql.util.ChainedSqlOperatorTable;
-import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql2rel.RelDecorrelator;
 import org.apache.calcite.sql2rel.SqlRexConvertletTable;
@@ -57,7 +56,6 @@ import org.apache.calcite.tools.FrameworkConfig;
 import org.apache.calcite.tools.Planner;
 import org.apache.calcite.tools.Program;
 import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.tools.RelConversionException;
 import org.apache.calcite.tools.ValidationException;
 import org.apache.calcite.util.Pair;
 
@@ -79,6 +77,7 @@ public class PlannerImpl implements Planner, ViewExpander {
   private final ImmutableList<RelTraitDef> traitDefs;
 
   private final SqlParser.Config parserConfig;
+  private final SqlValidator.Config sqlValidatorConfig;
   private final SqlToRelConverter.Config sqlToRelConverterConfig;
   private final SqlRexConvertletTable convertletTable;
 
@@ -108,6 +107,7 @@ public class PlannerImpl implements Planner, ViewExpander {
     this.operatorTable = config.getOperatorTable();
     this.programs = config.getPrograms();
     this.parserConfig = config.getParserConfig();
+    this.sqlValidatorConfig = config.getSqlValidatorConfig();
     this.sqlToRelConverterConfig = config.getSqlToRelConverterConfig();
     this.state = State.STATE_0_CLOSED;
     this.traitDefs = config.getTraitDefs();
@@ -222,10 +222,6 @@ public class PlannerImpl implements Planner, ViewExpander {
     return validatedSqlNode;
   }
 
-  private SqlConformance conformance() {
-    return connectionConfig.conformance();
-  }
-
   public Pair<SqlNode, RelDataType> validateAndGetType(SqlNode sqlNode)
       throws ValidationException {
     final SqlNode validatedNode = this.validate(sqlNode);
@@ -235,11 +231,11 @@ public class PlannerImpl implements Planner, ViewExpander 
{
   }
 
   @SuppressWarnings("deprecation")
-  public final RelNode convert(SqlNode sql) throws RelConversionException {
+  public final RelNode convert(SqlNode sql) {
     return rel(sql).rel;
   }
 
-  public RelRoot rel(SqlNode sql) throws RelConversionException {
+  public RelRoot rel(SqlNode sql) {
     ensure(State.STATE_4_VALIDATED);
     assert validatedSqlNode != null;
     final RexBuilder rexBuilder = createRexBuilder();
@@ -325,13 +321,16 @@ public class PlannerImpl implements Planner, ViewExpander 
{
   }
 
   private SqlValidator createSqlValidator(CalciteCatalogReader catalogReader) {
-    final SqlConformance conformance = conformance();
     final SqlOperatorTable opTab =
         ChainedSqlOperatorTable.of(operatorTable, catalogReader);
-    final SqlValidator validator =
-        new CalciteSqlValidator(opTab, catalogReader, typeFactory, 
conformance);
-    validator.setIdentifierExpansion(true);
-    return validator;
+    return new CalciteSqlValidator(opTab,
+        catalogReader,
+        typeFactory,
+        sqlValidatorConfig
+            .withDefaultNullCollation(connectionConfig.defaultNullCollation())
+            
.withLenientOperatorLookup(connectionConfig.lenientOperatorLookup())
+            .withSqlConformance(connectionConfig.conformance())
+            .withIdentifierExpansion(true));
   }
 
   private static SchemaPlus rootSchema(SchemaPlus schema) {
@@ -353,7 +352,7 @@ public class PlannerImpl implements Planner, ViewExpander {
   }
 
   public RelNode transform(int ruleSetIndex, RelTraitSet requiredOutputTraits,
-      RelNode rel) throws RelConversionException {
+      RelNode rel) {
     ensure(State.STATE_5_CONVERTED);
     rel.getCluster().setMetadataProvider(
         new CachingRelMetadataProvider(
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java 
b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index 5d0363b..bd70dd4 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -294,4 +294,12 @@ public class SqlCallBinding extends SqlOperatorBinding {
       Resources.ExInst<SqlValidatorException> ex) {
     return validator.newValidationError(call, ex);
   }
+
+  /**
+   * Returns whether to allow implicit type coercion when validation.
+   * This is a short-cut method.
+   */
+  public boolean isTypeCoercionEnabled() {
+    return validator.config().typeCoercionEnabled();
+  }
 }
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java 
b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 8c2be4a..55706d4 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -276,7 +276,7 @@ public class SqlFunction extends SqlOperator {
 
       validCoercionType:
       if (function == null) {
-        if (validator.isTypeCoercionEnabled()) {
+        if (validator.config().typeCoercionEnabled()) {
           // try again if implicit type coercion is allowed.
           function = (SqlFunction)
               SqlUtil.lookupRoutine(validator.getOperatorTable(), 
getNameAsId(),
@@ -304,7 +304,7 @@ public class SqlFunction extends SqlOperator {
 
         // if function doesn't exist within operator table and known function
         // handling is turned off then create a more permissive function
-        if (function == null && validator.isLenientOperatorLookup()) {
+        if (function == null && validator.config().lenientOperatorLookup()) {
           function = new SqlUnresolvedFunction(identifier, null,
               null, OperandTypes.VARIADIC, null, x.getFunctionType());
           break validCoercionType;
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java 
b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index 3c96f02..2506254 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -674,9 +674,7 @@ public abstract class SqlOperator {
         if (operand.e != null
             && operand.e.getKind() == SqlKind.DEFAULT
             && !operandTypeChecker.isOptional(operand.i)) {
-          throw callBinding.getValidator().newValidationError(
-              callBinding.getCall(),
-              RESOURCE.defaultForOptionalParameter());
+          throw 
callBinding.newValidationError(RESOURCE.defaultForOptionalParameter());
         }
       }
     }
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java 
b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
index c9e04f9..710b56f 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
@@ -557,8 +557,8 @@ public class SqlWindow extends SqlCall {
 
     for (SqlNode orderItem : orderList) {
       boolean savedColumnReferenceExpansion =
-          validator.getColumnReferenceExpansion();
-      validator.setColumnReferenceExpansion(false);
+          validator.config().columnReferenceExpansion();
+      validator.transform(config -> 
config.withColumnReferenceExpansion(false));
       try {
         orderItem.accept(Util.OverFinder.INSTANCE);
       } catch (ControlFlowException e) {
@@ -569,8 +569,8 @@ public class SqlWindow extends SqlCall {
       try {
         orderItem.validateExpr(validator, scope);
       } finally {
-        validator.setColumnReferenceExpansion(
-            savedColumnReferenceExpansion);
+        validator.transform(config ->
+            
config.withColumnReferenceExpansion(savedColumnReferenceExpansion));
       }
     }
 
diff --git 
a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java 
b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
index 98288b9..37ee866 100644
--- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorValidator.java
@@ -28,7 +28,6 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.OverScope;
 import org.apache.calcite.sql.validate.SelectScope;
-import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlModality;
 import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
@@ -61,14 +60,14 @@ public class SqlAdvisorValidator extends SqlValidatorImpl {
    * @param opTab         Operator table
    * @param catalogReader Catalog reader
    * @param typeFactory   Type factory
-   * @param conformance   Compatibility mode
+   * @param config        Config
    */
   public SqlAdvisorValidator(
       SqlOperatorTable opTab,
       SqlValidatorCatalogReader catalogReader,
       RelDataTypeFactory typeFactory,
-      SqlConformance conformance) {
-    super(opTab, catalogReader, typeFactory, conformance);
+      Config config) {
+    super(opTab, catalogReader, typeFactory, config);
   }
 
   //~ Methods ----------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
index 7be40dc..7d5c567 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java
@@ -207,7 +207,7 @@ public class SqlCaseOperator extends SqlOperator {
     if (!foundNotNull) {
       // according to the sql standard we can not have all of the THEN
       // statements and the ELSE returning null
-      if (throwOnFailure && 
!callBinding.getValidator().isTypeCoercionEnabled()) {
+      if (throwOnFailure && !callBinding.isTypeCoercionEnabled()) {
         throw callBinding.newError(RESOURCE.mustNotNullInElse());
       }
       return false;
@@ -264,7 +264,7 @@ public class SqlCaseOperator extends SqlOperator {
     RelDataType ret = typeFactory.leastRestrictive(argTypes);
     if (null == ret) {
       boolean coerced = false;
-      if (callBinding.getValidator().isTypeCoercionEnabled()) {
+      if (callBinding.isTypeCoercionEnabled()) {
         TypeCoercion typeCoercion = 
callBinding.getValidator().getTypeCoercion();
         RelDataType commonType = typeCoercion.getWiderTypeFor(argTypes, true);
         // commonType is always with nullability as false, we do not consider 
the
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
index 48859d0..0c894f6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
@@ -114,7 +114,7 @@ public class SqlInOperator extends SqlBinaryOperator {
       // First check that the expressions in the IN list are compatible
       // with each other. Same rules as the VALUES operator (per
       // SQL:2003 Part 2 Section 8.4, <in predicate>).
-      if (null == rightType && validator.isTypeCoercionEnabled()) {
+      if (null == rightType && validator.config().typeCoercionEnabled()) {
         // Do implicit type cast if it is allowed to.
         rightType = validator.getTypeCoercion().getWiderTypeFor(rightTypeList, 
true);
       }
@@ -131,7 +131,7 @@ public class SqlInOperator extends SqlBinaryOperator {
     }
     SqlCallBinding callBinding = new SqlCallBinding(validator, scope, call);
     // Coerce type first.
-    if (callBinding.getValidator().isTypeCoercionEnabled()) {
+    if (callBinding.isTypeCoercionEnabled()) {
       boolean coerced = callBinding.getValidator().getTypeCoercion()
           .inOperationCoercion(callBinding);
       if (coerced) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/ComparableOperandTypeChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/ComparableOperandTypeChecker.java
index c3f7b41..a3a2b22 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/ComparableOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/ComparableOperandTypeChecker.java
@@ -64,7 +64,7 @@ public class ComparableOperandTypeChecker extends 
SameOperandTypeChecker {
     }
     if (b) {
       // Coerce type first.
-      if (callBinding.getValidator().isTypeCoercionEnabled()) {
+      if (callBinding.isTypeCoercionEnabled()) {
         TypeCoercion typeCoercion = 
callBinding.getValidator().getTypeCoercion();
         // For comparison operators, i.e. >, <, =, >=, <=.
         typeCoercion.binaryComparisonCoercion(callBinding);
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
index 96d0df9..4bfad35 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
@@ -240,7 +240,7 @@ public class CompositeOperandTypeChecker implements 
SqlOperandTypeChecker {
     // 1. Check eagerly for binary arithmetic expressions.
     // 2. Check the comparability.
     // 3. Check if the operands have the right type.
-    if (callBinding.getValidator().isTypeCoercionEnabled()) {
+    if (callBinding.isTypeCoercionEnabled()) {
       final TypeCoercion typeCoercion = 
callBinding.getValidator().getTypeCoercion();
       typeCoercion.binaryArithmeticCoercion(callBinding);
     }
@@ -292,7 +292,7 @@ public class CompositeOperandTypeChecker implements 
SqlOperandTypeChecker {
             callBinding.getCall().operand(ord.i),
             0,
             false)) {
-          if (callBinding.getValidator().isTypeCoercionEnabled()) {
+          if (callBinding.isTypeCoercionEnabled()) {
             // Try type coercion for the call,
             // collect SqlTypeFamily and data type of all the operands.
             final List<SqlTypeFamily> families = allowedRules.stream()
@@ -348,7 +348,7 @@ public class CompositeOperandTypeChecker implements 
SqlOperandTypeChecker {
   }
 
   private boolean checkWithoutTypeCoercion(SqlCallBinding callBinding) {
-    if (!callBinding.getValidator().isTypeCoercionEnabled()) {
+    if (!callBinding.isTypeCoercionEnabled()) {
       return false;
     }
     for (SqlOperandTypeChecker rule : allowedRules) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java 
b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
index eeb67a8..a37848d 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
@@ -71,7 +71,7 @@ public class FamilyOperandTypeChecker implements 
SqlSingleOperandTypeChecker,
       return true;
     }
     if (SqlUtil.isNullLiteral(node, false)) {
-      if (callBinding.getValidator().isTypeCoercionEnabled()) {
+      if (callBinding.isTypeCoercionEnabled()) {
         return true;
       } else if (throwOnFailure) {
         throw callBinding.getValidator().newValidationError(node,
@@ -116,7 +116,7 @@ public class FamilyOperandTypeChecker implements 
SqlSingleOperandTypeChecker,
           false)) {
         // try to coerce type if it is allowed.
         boolean coerced = false;
-        if (callBinding.getValidator().isTypeCoercionEnabled()) {
+        if (callBinding.isTypeCoercionEnabled()) {
           TypeCoercion typeCoercion = 
callBinding.getValidator().getTypeCoercion();
           ImmutableList.Builder<RelDataType> builder = ImmutableList.builder();
           for (int i = 0; i < callBinding.getOperandCount(); i++) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java
 
b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java
index 0cdba4d..8896a0a 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java
@@ -61,7 +61,7 @@ public class SameOperandTypeExceptLastOperandChecker extends 
SameOperandTypeChec
         getOperandList(operatorBinding.getOperandCount());
     for (int i : operandList) {
       if (operatorBinding.isOperandNull(i, false)) {
-        if (callBinding.getValidator().isTypeCoercionEnabled()) {
+        if (callBinding.isTypeCoercionEnabled()) {
           types[i] = operatorBinding.getTypeFactory()
               .createSqlType(SqlTypeName.NULL);
         } else if (throwOnFailure) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java 
b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
index c447714..cc27d9b 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
@@ -114,7 +114,7 @@ public class SetopOperandTypeChecker implements 
SqlOperandTypeChecker {
           callBinding.getTypeFactory().leastRestrictive(columnIthTypes);
       if (type == null) {
         boolean coerced = false;
-        if (validator.isTypeCoercionEnabled()) {
+        if (callBinding.isTypeCoercionEnabled()) {
           for (int j = 0; j < callBinding.getOperandCount(); j++) {
             TypeCoercion typeCoercion = validator.getTypeCoercion();
             RelDataType widenType = 
typeCoercion.getWiderTypeFor(columnIthTypes, true);
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java 
b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
index 13c1875..b9e9b1a 100644
--- 
a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
+++ 
b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java
@@ -184,7 +184,7 @@ public class IdentifierNamespace extends AbstractNamespace {
     resolvedNamespace = Objects.requireNonNull(resolveImpl(id));
     if (resolvedNamespace instanceof TableNamespace) {
       SqlValidatorTable table = resolvedNamespace.getTable();
-      if (validator.shouldExpandIdentifiers()) {
+      if (validator.config().identifierExpansion()) {
         // TODO:  expand qualifiers for column references also
         List<String> qualifiedNames = table.getQualifiedName();
         if (qualifiedNames != null) {
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/OrderByScope.java 
b/core/src/main/java/org/apache/calcite/sql/validate/OrderByScope.java
index 70d8982..222fd0e 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/OrderByScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/OrderByScope.java
@@ -70,7 +70,7 @@ public class OrderByScope extends DelegatingScope {
   public SqlQualified fullyQualify(SqlIdentifier identifier) {
     // If it's a simple identifier, look for an alias.
     if (identifier.isSimple()
-        && validator.getConformance().isSortByAlias()) {
+        && validator.config().sqlConformance().isSortByAlias()) {
       final String name = identifier.names.get(0);
       final SqlValidatorNamespace selectNs =
           validator.getNamespace(select);
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
index c616a5a..e461034 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
@@ -44,9 +44,13 @@ import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
 import org.apache.calcite.sql.type.SqlTypeCoercionRule;
 import org.apache.calcite.sql.validate.implicit.TypeCoercion;
+import org.apache.calcite.util.ImmutableBeans;
+
+import org.apiguardian.api.API;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.UnaryOperator;
 import javax.annotation.Nullable;
 
 /**
@@ -112,7 +116,10 @@ public interface SqlValidator {
    * Default is {@link SqlConformanceEnum#DEFAULT}.
    *
    * @return dialect of SQL this validator recognizes
+   *
+   * @deprecated Use {@link Config#sqlConformance}
    */
+  @Deprecated // to be removed before 1.24
   SqlConformance getConformance();
 
   /**
@@ -620,7 +627,10 @@ public interface SqlValidator {
    * references.
    *
    * @param expandIdentifiers new setting
+   *
+   * @deprecated Use {@link Config#withIdentifierExpansion}
    */
+  @Deprecated // to be removed before 1.24
   void setIdentifierExpansion(boolean expandIdentifiers);
 
   /**
@@ -628,34 +638,56 @@ public interface SqlValidator {
    * not apply to the ORDER BY clause; may be fixed in the future.)
    *
    * @param expandColumnReferences new setting
+   *
+   * @deprecated Use {@link Config#columnReferenceExpansion}
    */
+  @Deprecated // to be removed before 1.24
   void setColumnReferenceExpansion(boolean expandColumnReferences);
 
   /**
    * @return whether column reference expansion is enabled
+   *
+   * @deprecated  Use {@link Config#columnReferenceExpansion}
    */
+  @Deprecated // to be removed before 1.24
   boolean getColumnReferenceExpansion();
 
-  /** Sets how NULL values should be collated if an ORDER BY item does not
-   * contain NULLS FIRST or NULLS LAST. */
+  /**
+   * Sets how NULL values should be collated if an ORDER BY item does not
+   * contain NULLS FIRST or NULLS LAST.
+   *
+   * @deprecated Use {@link Config#defaultNullCollation}
+   */
+  @Deprecated // to be removed before 1.24
   void setDefaultNullCollation(NullCollation nullCollation);
 
-  /** Returns how NULL values should be collated if an ORDER BY item does not
-   * contain NULLS FIRST or NULLS LAST. */
+  /**
+   * Returns how NULL values should be collated if an ORDER BY item does not
+   * contain NULLS FIRST or NULLS LAST.
+   *
+   * @deprecated Use {@link Config#defaultNullCollation}
+   */
+  @Deprecated // to be removed before 1.24
   NullCollation getDefaultNullCollation();
 
   /**
    * Returns expansion of identifiers.
    *
    * @return whether this validator should expand identifiers
+   *
+   * @deprecated Use {@link Config#identifierExpansion}
    */
+  @Deprecated // to be removed before 1.24
   boolean shouldExpandIdentifiers();
 
   /**
    * Enables or disables rewrite of "macro-like" calls such as COALESCE.
    *
    * @param rewriteCalls new setting
+   *
+   * @deprecated Use {@link Config#callRewrite}
    */
+  @Deprecated // to be removed before 1.24
   void setCallRewrite(boolean rewriteCalls);
 
   /**
@@ -787,7 +819,10 @@ public interface SqlValidator {
    * function.
    *
    * @param lenient Whether to be lenient when encountering an unknown function
+   *
+   * @deprecated Use {@link Config#withLenientOperatorLookup}
    */
+  @Deprecated // to be removed before 1.24
   SqlValidator setLenientOperatorLookup(boolean lenient);
 
   /** Returns whether this validator should be lenient upon encountering an
@@ -800,7 +835,11 @@ public interface SqlValidator {
    * {@link #getUnknownType() UNKNOWN}.
    *
    * <p>If false (the default behavior), an unknown function call causes a
-   * validation error to be thrown. */
+   * validation error to be thrown.
+   *
+   * @deprecated Use {@link Config#lenientOperatorLookup}
+   */
+  @Deprecated // to be removed before 1.24
   boolean isLenientOperatorLookup();
 
   /**
@@ -809,10 +848,18 @@ public interface SqlValidator {
    * @param enabled if enable the type coercion, default is true
    *
    * @see org.apache.calcite.sql.validate.implicit.TypeCoercionImpl 
TypeCoercionImpl
+   *
+   * @deprecated Use {@link Config#withTypeCoercionEnabled}
    */
+  @Deprecated // to be removed before 1.24
   SqlValidator setEnableTypeCoercion(boolean enabled);
 
-  /** Returns if this validator supports implicit type coercion. */
+  /**
+   * Returns if this validator supports implicit type coercion.
+   *
+   * @deprecated Use {@link Config#typeCoercionEnabled}
+   */
+  @Deprecated // to be removed before 1.24
   boolean isTypeCoercionEnabled();
 
   /**
@@ -839,4 +886,128 @@ public interface SqlValidator {
    *                          for how to customize the rules.
    */
   void setSqlTypeCoercionRules(SqlTypeCoercionRule typeCoercionRules);
+
+  /** Returns the config of the validator. */
+  Config config();
+
+  /**
+   * Returns this SqlValidator, with the same state, applying
+   * a transform to the config.
+   *
+   * <p>This is mainly used for tests, otherwise constructs a {@link Config} 
directly
+   * through the constructor.
+   */
+  @API(status = API.Status.INTERNAL, since = "1.23")
+  SqlValidator transform(UnaryOperator<SqlValidator.Config> transform);
+
+  //~ Inner Class ------------------------------------------------------------
+
+  /**
+   * Interface to define the configuration for a SqlValidator.
+   * Provides methods to set each configuration option.
+   */
+  public interface Config {
+    /** Default configuration. */
+    SqlValidator.Config DEFAULT = ImmutableBeans.create(Config.class);
+
+    /**
+     * Returns whether to enable rewrite of "macro-like" calls such as 
COALESCE.
+     */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(true)
+    boolean callRewrite();
+
+    /**
+     * Sets whether to enable rewrite of "macro-like" calls such as COALESCE.
+     */
+    Config withCallRewrite(boolean rewrite);
+
+    /** Returns how NULL values should be collated if an ORDER BY item does not
+     * contain NULLS FIRST or NULLS LAST. */
+    @ImmutableBeans.Property
+    @ImmutableBeans.EnumDefault("HIGH")
+    NullCollation defaultNullCollation();
+
+    /** Sets how NULL values should be collated if an ORDER BY item does not
+     * contain NULLS FIRST or NULLS LAST. */
+    Config withDefaultNullCollation(NullCollation nullCollation);
+
+    /**
+     * Returns whether column reference expansion is enabled
+     */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(true)
+    boolean columnReferenceExpansion();
+
+    /**
+     * Sets whether to enable expansion of column references. (Currently this 
does
+     * not apply to the ORDER BY clause; may be fixed in the future.)
+     */
+    Config withColumnReferenceExpansion(boolean expand);
+
+    /**
+     * Returns whether to expand identifiers other than column
+     * references.
+     *
+     * <p>REVIEW jvs 30-June-2006: subclasses may override 
shouldExpandIdentifiers
+     * in a way that ignores this; we should probably get rid of the protected
+     * method and always use this variable (or better, move preferences like
+     * this to a separate "parameter" class).
+     */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(false)
+    boolean identifierExpansion();
+
+    /**
+     * Sets whether to enable expansion of identifiers other than column
+     * references.
+     */
+    Config withIdentifierExpansion(boolean expand);
+
+    /**
+     * Returns whether this validator should be lenient upon encountering an
+     * unknown function, default false.
+     *
+     * <p>If true, if a statement contains a call to a function that is not
+     * present in the operator table, or if the call does not have the required
+     * number or types of operands, the validator nevertheless regards the
+     * statement as valid. The type of the function call will be
+     * {@link #getUnknownType() UNKNOWN}.
+     *
+     * <p>If false (the default behavior), an unknown function call causes a
+     * validation error to be thrown.
+     */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(false)
+    boolean lenientOperatorLookup();
+
+    /**
+     * Sets whether this validator should be lenient upon encountering an 
unknown
+     * function.
+     *
+     * @param lenient Whether to be lenient when encountering an unknown 
function
+     */
+    Config withLenientOperatorLookup(boolean lenient);
+
+    /** Returns whether the validator supports implicit type coercion. */
+    @ImmutableBeans.Property
+    @ImmutableBeans.BooleanDefault(true)
+    boolean typeCoercionEnabled();
+
+    /**
+     * Sets whether to enable implicit type coercion for validation, default 
true.
+     *
+     * @see org.apache.calcite.sql.validate.implicit.TypeCoercionImpl 
TypeCoercionImpl
+     */
+    Config withTypeCoercionEnabled(boolean enabled);
+
+    /** Returns the dialect of SQL (SQL:2003, etc.) this validator recognizes.
+     * Default is {@link SqlConformanceEnum#DEFAULT}. */
+    @ImmutableBeans.Property
+    @ImmutableBeans.EnumDefault("DEFAULT")
+    SqlConformance sqlConformance();
+
+    /** Sets up the sql conformance of the validator. */
+    Config withSqlConformance(SqlConformance conformance);
+  }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 7722363..cbd167c 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -132,6 +132,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -261,22 +262,12 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
   private final AggFinder aggOrOverOrGroupFinder;
   private final AggFinder groupFinder;
   private final AggFinder overFinder;
-  private final SqlConformance conformance;
-  private final Map<SqlNode, SqlNode> originalExprs = new HashMap<>();
-
-  private SqlNode top;
-
-  // REVIEW jvs 30-June-2006: subclasses may override shouldExpandIdentifiers
-  // in a way that ignores this; we should probably get rid of the protected
-  // method and always use this variable (or better, move preferences like
-  // this to a separate "parameter" class)
-  protected boolean expandIdentifiers;
 
-  protected boolean expandColumnReferences;
+  private Config config;
 
-  protected boolean lenientOperatorLookup;
+  private final Map<SqlNode, SqlNode> originalExprs = new HashMap<>();
 
-  private boolean rewriteCalls;
+  private SqlNode top;
 
   private NullCollation nullCollation = NullCollation.HIGH;
 
@@ -292,9 +283,6 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
   // TypeCoercion instance used for implicit type coercion.
   private TypeCoercion typeCoercion;
 
-  // Flag saying if we enable the implicit type coercion.
-  private boolean enableTypeCoercion;
-
   //~ Constructors -----------------------------------------------------------
 
   /**
@@ -303,23 +291,21 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
    * @param opTab         Operator table
    * @param catalogReader Catalog reader
    * @param typeFactory   Type factory
-   * @param conformance   Compatibility mode
+   * @param config        Config
    */
   protected SqlValidatorImpl(
       SqlOperatorTable opTab,
       SqlValidatorCatalogReader catalogReader,
       RelDataTypeFactory typeFactory,
-      SqlConformance conformance) {
+      Config config) {
     this.opTab = Objects.requireNonNull(opTab);
     this.catalogReader = Objects.requireNonNull(catalogReader);
     this.typeFactory = Objects.requireNonNull(typeFactory);
-    this.conformance = Objects.requireNonNull(conformance);
+    this.config = Objects.requireNonNull(config);
 
     unknownType = typeFactory.createUnknownType();
     booleanType = typeFactory.createSqlType(SqlTypeName.BOOLEAN);
 
-    rewriteCalls = true;
-    expandColumnReferences = true;
     final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
     aggFinder = new AggFinder(opTab, false, true, false, null, nameMatcher);
     aggOrOverFinder =
@@ -329,17 +315,30 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     groupFinder = new AggFinder(opTab, false, false, true, null, nameMatcher);
     aggOrOverOrGroupFinder = new AggFinder(opTab, true, true, true, null,
         nameMatcher);
-    this.lenientOperatorLookup = catalogReader.getConfig() != null
-        && catalogReader.getConfig().lenientOperatorLookup();
-    this.enableTypeCoercion = catalogReader.getConfig() == null
-        || catalogReader.getConfig().typeCoercion();
-    this.typeCoercion = TypeCoercions.getTypeCoercion(this, conformance);
+    this.typeCoercion = TypeCoercions.getTypeCoercion(this, 
config.sqlConformance());
+  }
+
+  /**
+   * Creates a validator.
+   *
+   * @param opTab         Operator table
+   * @param catalogReader Catalog reader
+   * @param typeFactory   Type factory
+   * @param conformance   Compatibility mode
+   */
+  @Deprecated // to be removed before 1.24
+  protected SqlValidatorImpl(
+      SqlOperatorTable opTab,
+      SqlValidatorCatalogReader catalogReader,
+      RelDataTypeFactory typeFactory,
+      SqlConformance conformance) {
+    this(opTab, catalogReader, typeFactory, 
Config.DEFAULT.withSqlConformance(conformance));
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public SqlConformance getConformance() {
-    return conformance;
+    return config.sqlConformance();
   }
 
   public SqlValidatorCatalogReader getCatalogReader() {
@@ -563,9 +562,8 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
 
     final SqlIdentifier identifier = (SqlIdentifier) selectItem;
-    final SqlConformance conformance = validator.getConformance();
     if (!identifier.isSimple()) {
-      if (!conformance.allowQualifyingCommonColumn()) {
+      if (!validator.config().sqlConformance().allowQualifyingCommonColumn()) {
         validateQualifiedCommonColumn((SqlJoin) from, identifier, scope, 
validator);
       }
       return selectItem;
@@ -1307,7 +1305,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
           ((SqlBasicCall) call).setOperator(overloads.get(0));
         }
       }
-      if (rewriteCalls) {
+      if (config.callRewrite()) {
         node = call.getOperator().rewriteCall(this, call);
       }
     } else if (node instanceof SqlNodeList) {
@@ -1836,7 +1834,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
       assert type == returnType;
     }
 
-    if (shouldExpandIdentifiers()) {
+    if (config.identifierExpansion()) {
       if (resolvedConstructor != null) {
         ((SqlBasicCall) call).setOperator(resolvedConstructor);
       } else {
@@ -1898,7 +1896,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     if ((node instanceof SqlDynamicParam) || isNullLiteral) {
       if (inferredType.equals(unknownType)) {
         if (isNullLiteral) {
-          if (enableTypeCoercion) {
+          if (config.typeCoercionEnabled()) {
             // derive type of null literal
             deriveType(scope, node);
             return;
@@ -2021,35 +2019,35 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
 
   // implement SqlValidator
   public void setIdentifierExpansion(boolean expandIdentifiers) {
-    this.expandIdentifiers = expandIdentifiers;
+    this.config = this.config.withIdentifierExpansion(expandIdentifiers);
   }
 
   // implement SqlValidator
   public void setColumnReferenceExpansion(
       boolean expandColumnReferences) {
-    this.expandColumnReferences = expandColumnReferences;
+    this.config = 
this.config.withColumnReferenceExpansion(expandColumnReferences);
   }
 
   // implement SqlValidator
   public boolean getColumnReferenceExpansion() {
-    return expandColumnReferences;
+    return this.config.columnReferenceExpansion();
   }
 
   public void setDefaultNullCollation(NullCollation nullCollation) {
-    this.nullCollation = Objects.requireNonNull(nullCollation);
+    this.config = 
this.config.withDefaultNullCollation(Objects.requireNonNull(nullCollation));
   }
 
   public NullCollation getDefaultNullCollation() {
-    return nullCollation;
+    return this.config.defaultNullCollation();
   }
 
   // implement SqlValidator
   public void setCallRewrite(boolean rewriteCalls) {
-    this.rewriteCalls = rewriteCalls;
+    this.config = this.config.withCallRewrite(rewriteCalls);
   }
 
   public boolean shouldExpandIdentifiers() {
-    return expandIdentifiers;
+    return this.config.identifierExpansion();
   }
 
   protected boolean shouldAllowIntermediateOrderBy() {
@@ -2165,7 +2163,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
         if (alias == null) {
           alias = deriveAlias(node, nextGeneratedId++);
         }
-        if (shouldExpandIdentifiers()) {
+        if (config.identifierExpansion()) {
           newNode = SqlValidatorUtil.addAlias(node, alias);
         }
         break;
@@ -2183,7 +2181,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
         // give this anonymous construct a name since later
         // query processing stages rely on it
         alias = deriveAlias(node, nextGeneratedId++);
-        if (shouldExpandIdentifiers()) {
+        if (config.identifierExpansion()) {
           // Since we're expanding identifiers, we should make the
           // aliases explicit too, otherwise the expanded query
           // will not be consistent if we convert back to SQL, e.g.
@@ -3074,7 +3072,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
 
   public void validateIdentifier(SqlIdentifier id, SqlValidatorScope scope) {
     final SqlQualified fqId = scope.fullyQualify(id);
-    if (expandColumnReferences) {
+    if (this.config.columnReferenceExpansion()) {
       // NOTE jvs 9-Apr-2007: this doesn't cover ORDER BY, which has its
       // own ideas about qualification.
       id.assignNamesFrom(fqId.identifier);
@@ -3371,7 +3369,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     // a NATURAL keyword?
     switch (joinType) {
     case LEFT_SEMI_JOIN:
-      if (!conformance.isLiberal()) {
+      if (!this.config.sqlConformance().isLiberal()) {
         throw newValidationError(join.getJoinTypeNode(),
             RESOURCE.dialectDoesNotSupportFeature("LEFT SEMI JOIN"));
       }
@@ -3503,7 +3501,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
 
     if (select.getFrom() == null) {
-      if (conformance.isFromRequired()) {
+      if (this.config.sqlConformance().isFromRequired()) {
         throw newValidationError(select, RESOURCE.selectMissingFrom());
       }
     } else {
@@ -3964,21 +3962,21 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
   }
 
   public SqlValidator setLenientOperatorLookup(boolean lenient) {
-    this.lenientOperatorLookup = lenient;
+    this.config = this.config.withLenientOperatorLookup(lenient);
     return this;
   }
 
   public boolean isLenientOperatorLookup() {
-    return this.lenientOperatorLookup;
+    return this.config.lenientOperatorLookup();
   }
 
   public SqlValidator setEnableTypeCoercion(boolean enabled) {
-    this.enableTypeCoercion = enabled;
+    this.config = this.config.withTypeCoercionEnabled(enabled);
     return this;
   }
 
   public boolean isTypeCoercionEnabled() {
-    return this.enableTypeCoercion;
+    return this.config.typeCoercionEnabled();
   }
 
   public void setTypeCoercion(TypeCoercion typeCoercion) {
@@ -3987,7 +3985,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
   }
 
   public TypeCoercion getTypeCoercion() {
-    assert isTypeCoercionEnabled();
+    assert config.typeCoercionEnabled();
     return this.typeCoercion;
   }
 
@@ -3995,6 +3993,15 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     SqlTypeCoercionRule.THREAD_PROVIDERS.set(typeCoercionRules);
   }
 
+  public Config config() {
+    return this.config;
+  }
+
+  public SqlValidator transform(UnaryOperator<Config> transform) {
+    this.config = transform.apply(this.config);
+    return this;
+  }
+
   /**
    * Validates the ORDER BY clause of a SELECT statement.
    *
@@ -4203,7 +4210,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
     final AggregatingScope havingScope =
         (AggregatingScope) getSelectScope(select);
-    if (getConformance().isHavingAlias()) {
+    if (config.sqlConformance().isHavingAlias()) {
       SqlNode newExpr = expandGroupByOrHavingExpr(having, havingScope, select, 
true);
       if (having != newExpr) {
         having = newExpr;
@@ -4270,7 +4277,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
         new SqlNodeList(
             expandedSelectItems,
             selectItems.getParserPosition());
-    if (shouldExpandIdentifiers()) {
+    if (config.identifierExpansion()) {
       select.setSelectList(newSelectList);
     }
     getRawSelectScope(select).setExpandedSelectList(expandedSelectItems);
@@ -4656,7 +4663,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
       RelDataType targetRowType,
       SqlInsert insert) {
     if (insert.getTargetColumnList() == null
-        && conformance.isInsertSubsetColumnsAllowed()) {
+        && this.config.sqlConformance().isInsertSubsetColumnsAllowed()) {
       // Target an implicit subset of columns.
       final SqlNode source = insert.getSource();
       final RelDataType sourceRowType = getNamespace(source).getRowType();
@@ -4724,7 +4731,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
       // Returns early if source and target row type equals sans nullability.
       return;
     }
-    if (enableTypeCoercion && !isUpdateModifiableViewTable) {
+    if (config.typeCoercionEnabled() && !isUpdateModifiableViewTable) {
       // Try type coercion first if implicit type coercion is allowed.
       boolean coerced = typeCoercion.querySourceCoercion(sourceScope,
           sourceRowType,
@@ -4963,7 +4970,8 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
       }
 
       SqlCall rowConstructor = (SqlCall) operand;
-      if (conformance.isInsertSubsetColumnsAllowed() && 
targetRowType.isStruct()
+      if (this.config.sqlConformance().isInsertSubsetColumnsAllowed()
+          && targetRowType.isStruct()
           && rowConstructor.operandCount() < targetRowType.getFieldCount()) {
         targetRowType =
             typeFactory.createStructType(
@@ -5527,7 +5535,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     if ((call.operandCount() == 0)
         && (operator.getSyntax() == SqlSyntax.FUNCTION_ID)
         && !call.isExpanded()
-        && !conformance.allowNiladicParentheses()) {
+        && !this.config.sqlConformance().allowNiladicParentheses()) {
       // For example, "LOCALTIME()" is illegal. (It should be
       // "LOCALTIME", which would have been handled as a
       // SqlIdentifier.)
@@ -6051,7 +6059,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
       // Ordinal markers, e.g. 'select a, b from t order by 2'.
       // Only recognize them if they are the whole expression,
       // and if the dialect permits.
-      if (literal == root && getConformance().isSortByOrdinal()) {
+      if (literal == root && config.sqlConformance().isSortByOrdinal()) {
         switch (literal.getTypeName()) {
         case DECIMAL:
         case DOUBLE:
@@ -6100,7 +6108,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     public SqlNode visit(SqlIdentifier id) {
       // Aliases, e.g. 'select a as x, b from t order by x'.
       if (id.isSimple()
-          && getConformance().isSortByAlias()) {
+          && config.sqlConformance().isSortByAlias()) {
         String alias = id.getSimple();
         final SqlValidatorNamespace selectNs = getNamespace(select);
         final RelDataType rowType =
@@ -6172,8 +6180,8 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     @Override public SqlNode visit(SqlIdentifier id) {
       if (id.isSimple()
           && (havingExpr
-              ? validator.getConformance().isHavingAlias()
-              : validator.getConformance().isGroupByAlias())) {
+              ? validator.config().sqlConformance().isHavingAlias()
+              : validator.config().sqlConformance().isGroupByAlias())) {
         String name = id.getSimple();
         SqlNode expr = null;
         final SqlNameMatcher nameMatcher =
@@ -6215,7 +6223,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
     }
 
     public SqlNode visit(SqlLiteral literal) {
-      if (havingExpr || !validator.getConformance().isGroupByOrdinal()) {
+      if (havingExpr || 
!validator.config().sqlConformance().isGroupByOrdinal()) {
         return super.visit(literal);
       }
       boolean isOrdinalLiteral = literal == root;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index 8ff8a97..bd24da5 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -340,9 +340,9 @@ public class SqlValidatorUtil {
       SqlOperatorTable opTab,
       SqlValidatorCatalogReader catalogReader,
       RelDataTypeFactory typeFactory,
-      SqlConformance conformance) {
+      SqlValidator.Config config) {
     return new SqlValidatorImpl(opTab, catalogReader, typeFactory,
-        conformance);
+        config);
   }
 
   /**
@@ -354,7 +354,7 @@ public class SqlValidatorUtil {
       SqlValidatorCatalogReader catalogReader,
       RelDataTypeFactory typeFactory) {
     return newValidator(opTab, catalogReader, typeFactory,
-        SqlConformanceEnum.DEFAULT);
+        SqlValidator.Config.DEFAULT);
   }
 
   /**
@@ -1159,7 +1159,7 @@ public class SqlValidatorUtil {
     SqlValidator validator = newValidator(operatorTable,
         catalogReader,
         typeFactory,
-        SqlConformanceEnum.DEFAULT);
+        SqlValidator.Config.DEFAULT);
     final SqlSelect select = (SqlSelect) validator.validate(select0);
     assert select.getSelectList().size() == 1
         : "Expression " + expr + " should be atom expression";
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java 
b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 6d5f336..3f3bbb4 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -2276,7 +2276,7 @@ public class SqlToRelConverter {
         break;
       }
       final RelFieldCollation.NullDirection nullDirection =
-          validator.getDefaultNullCollation().last(desc(direction))
+          validator.config().defaultNullCollation().last(desc(direction))
               ? RelFieldCollation.NullDirection.LAST
               : RelFieldCollation.NullDirection.FIRST;
       RexNode e = matchBb.convertExpression(order);
@@ -3285,7 +3285,7 @@ public class SqlToRelConverter {
 
     switch (nullDirection) {
     case UNSPECIFIED:
-      nullDirection = validator.getDefaultNullCollation().last(desc(direction))
+      nullDirection = 
validator.config().defaultNullCollation().last(desc(direction))
           ? RelFieldCollation.NullDirection.LAST
           : RelFieldCollation.NullDirection.FIRST;
     }
@@ -3702,7 +3702,7 @@ public class SqlToRelConverter {
     final RelDataType tableRowType = targetTable.getRowType();
     SqlNodeList targetColumnList = call.getTargetColumnList();
     if (targetColumnList == null) {
-      if (validator.getConformance().isInsertSubsetColumnsAllowed()) {
+      if (validator.config().sqlConformance().isInsertSubsetColumnsAllowed()) {
         final RelDataType targetRowType =
             typeFactory.createStructType(
                 tableRowType.getFieldList()
@@ -4873,12 +4873,12 @@ public class SqlToRelConverter {
         switch (nullDirection) {
         case UNSPECIFIED:
           final RelFieldCollation.NullDirection nullDefaultDirection =
-              validator.getDefaultNullCollation().last(desc(direction))
+              validator.config().defaultNullCollation().last(desc(direction))
                   ? RelFieldCollation.NullDirection.LAST
                   : RelFieldCollation.NullDirection.FIRST;
           if (nullDefaultDirection != direction.defaultNullDirection()) {
             SqlKind nullDirectionSqlKind =
-                validator.getDefaultNullCollation().last(desc(direction))
+                validator.config().defaultNullCollation().last(desc(direction))
                     ? SqlKind.NULLS_LAST
                     : SqlKind.NULLS_FIRST;
             flags.add(nullDirectionSqlKind);
diff --git a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java 
b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
index ce4d852..67b21d6 100644
--- a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
+++ b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
@@ -26,6 +26,7 @@ import org.apache.calcite.rex.RexExecutor;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql2rel.SqlRexConvertletTable;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 
@@ -44,6 +45,11 @@ public interface FrameworkConfig {
   SqlParser.Config getParserConfig();
 
   /**
+   * The configuration of {@link SqlValidator}.
+   */
+  SqlValidator.Config getSqlValidatorConfig();
+
+  /**
    * The configuration of {@link SqlToRelConverter}.
    */
   SqlToRelConverter.Config getSqlToRelConverterConfig();
diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java 
b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
index fb3c3fe..3fd7e85 100644
--- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java
+++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
@@ -35,6 +35,7 @@ import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql2rel.SqlRexConvertletTable;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
@@ -218,6 +219,7 @@ public class Frameworks {
     private Context context;
     private ImmutableList<RelTraitDef> traitDefs;
     private SqlParser.Config parserConfig;
+    private SqlValidator.Config sqlValidatorConfig;
     private SqlToRelConverter.Config sqlToRelConverterConfig;
     private SchemaPlus defaultSchema;
     private RexExecutor executor;
@@ -234,6 +236,7 @@ public class Frameworks {
       programs = ImmutableList.of();
       context = Contexts.empty();
       parserConfig = SqlParser.Config.DEFAULT;
+      sqlValidatorConfig = SqlValidator.Config.DEFAULT;
       sqlToRelConverterConfig = SqlToRelConverter.Config.DEFAULT;
       typeSystem = RelDataTypeSystem.DEFAULT;
       evolveLattice = false;
@@ -248,6 +251,7 @@ public class Frameworks {
       context = config.getContext();
       traitDefs = config.getTraitDefs();
       parserConfig = config.getParserConfig();
+      sqlValidatorConfig = config.getSqlValidatorConfig();
       sqlToRelConverterConfig = config.getSqlToRelConverterConfig();
       defaultSchema = config.getDefaultSchema();
       executor = config.getExecutor();
@@ -259,7 +263,7 @@ public class Frameworks {
 
     public FrameworkConfig build() {
       return new StdFrameworkConfig(context, convertletTable, operatorTable,
-          programs, traitDefs, parserConfig, sqlToRelConverterConfig,
+          programs, traitDefs, parserConfig, sqlValidatorConfig, 
sqlToRelConverterConfig,
           defaultSchema, costFactory, typeSystem, executor, evolveLattice,
           statisticProvider, viewExpander);
     }
@@ -304,6 +308,11 @@ public class Frameworks {
       return this;
     }
 
+    public ConfigBuilder sqlValidatorConfig(SqlValidator.Config 
sqlValidatorConfig) {
+      this.sqlValidatorConfig = Objects.requireNonNull(sqlValidatorConfig);
+      return this;
+    }
+
     public ConfigBuilder sqlToRelConverterConfig(
         SqlToRelConverter.Config sqlToRelConverterConfig) {
       this.sqlToRelConverterConfig =
@@ -372,6 +381,7 @@ public class Frameworks {
     private final ImmutableList<Program> programs;
     private final ImmutableList<RelTraitDef> traitDefs;
     private final SqlParser.Config parserConfig;
+    private final SqlValidator.Config sqlValidatorConfig;
     private final SqlToRelConverter.Config sqlToRelConverterConfig;
     private final SchemaPlus defaultSchema;
     private final RelOptCostFactory costFactory;
@@ -387,6 +397,7 @@ public class Frameworks {
         ImmutableList<Program> programs,
         ImmutableList<RelTraitDef> traitDefs,
         SqlParser.Config parserConfig,
+        SqlValidator.Config sqlValidatorConfig,
         SqlToRelConverter.Config sqlToRelConverterConfig,
         SchemaPlus defaultSchema,
         RelOptCostFactory costFactory,
@@ -401,6 +412,7 @@ public class Frameworks {
       this.programs = programs;
       this.traitDefs = traitDefs;
       this.parserConfig = parserConfig;
+      this.sqlValidatorConfig = sqlValidatorConfig;
       this.sqlToRelConverterConfig = sqlToRelConverterConfig;
       this.defaultSchema = defaultSchema;
       this.costFactory = costFactory;
@@ -415,6 +427,10 @@ public class Frameworks {
       return parserConfig;
     }
 
+    public SqlValidator.Config getSqlValidatorConfig() {
+      return sqlValidatorConfig;
+    }
+
     public SqlToRelConverter.Config getSqlToRelConverterConfig() {
       return sqlToRelConverterConfig;
     }
diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java 
b/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java
index d9019a6..a7133cf 100644
--- a/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java
+++ b/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.util;
 
+import org.apache.calcite.sql.validate.SqlConformance;
+import org.apache.calcite.sql.validate.SqlConformanceEnum;
+
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSortedMap;
 
@@ -282,7 +285,11 @@ public class ImmutableBeans {
   }
 
   private static Object convertDefault(Object defaultValue, String 
propertyName,
-      Class propertyType) {
+      Class<?> propertyType) {
+    if (propertyType.equals(SqlConformance.class)) {
+      // Workaround for SqlConformance because it is actually not a Enum.
+      propertyType = SqlConformanceEnum.class;
+    }
     if (defaultValue == null || !propertyType.isEnum()) {
       return defaultValue;
     }
diff --git 
a/core/src/test/java/org/apache/calcite/rel/logical/ToLogicalConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/logical/ToLogicalConverterTest.java
index f4afd73..679d287 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/logical/ToLogicalConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/logical/ToLogicalConverterTest.java
@@ -28,7 +28,6 @@ import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.test.CalciteAssert;
 import org.apache.calcite.test.RelBuilderTest;
@@ -85,7 +84,6 @@ class ToLogicalConverterTest {
     final SchemaPlus schema = CalciteAssert.addSchema(rootSchema,
         CalciteAssert.SchemaSpec.JDBC_FOODMART);
     return Frameworks.newConfigBuilder()
-        .parserConfig(SqlParser.Config.DEFAULT)
         .defaultSchema(schema)
         .sqlToRelConverterConfig(DEFAULT_REL_CONFIG)
         .build();
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
index 51f4a86..d0f9788 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
@@ -54,8 +54,8 @@ import static org.junit.jupiter.api.Assertions.fail;
  */
 @ExtendWith(SqlValidatorTestCase.LexConfiguration.class)
 class SqlAdvisorTest extends SqlValidatorTestCase {
-  public static final SqlTestFactory ADVISOR_TEST_FACTORY = 
SqlTestFactory.INSTANCE.withValidator(
-      SqlAdvisorValidator::new);
+  public static final SqlTestFactory ADVISOR_TEST_FACTORY =
+      SqlTestFactory.INSTANCE.withValidator(SqlAdvisorValidator::new);
 
   private static final List<String> STAR_KEYWORD =
       Arrays.asList(
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
index 0800c97..81fa705 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
@@ -134,12 +134,14 @@ public class SqlTestFactory {
     final boolean lenientOperatorLookup =
         (boolean) options.get("lenientOperatorLookup");
     final boolean enableTypeCoercion = (boolean) 
options.get("enableTypeCoercion");
+    final SqlValidator.Config config = SqlValidator.Config.DEFAULT
+        .withSqlConformance(conformance)
+        .withTypeCoercionEnabled(enableTypeCoercion)
+        .withLenientOperatorLookup(lenientOperatorLookup);
     return validatorFactory.create(operatorTable.get(),
         catalogReader.get(),
         typeFactory.get(),
-        conformance)
-        .setEnableTypeCoercion(enableTypeCoercion)
-        .setLenientOperatorLookup(lenientOperatorLookup);
+        config);
   }
 
   public SqlAdvisor createAdvisor() {
@@ -206,7 +208,7 @@ public class SqlTestFactory {
         SqlOperatorTable opTab,
         SqlValidatorCatalogReader catalogReader,
         RelDataTypeFactory typeFactory,
-        SqlConformance conformance);
+        SqlValidator.Config config);
   }
 
   /**
diff --git a/core/src/test/java/org/apache/calcite/test/SqlTestGen.java 
b/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
index 6f733b0..40a1848 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
@@ -85,7 +85,7 @@ class SqlTestGen {
    */
   private static class SqlValidatorSpooler extends SqlValidatorTest {
     private static final SqlTestFactory SPOOLER_VALIDATOR = 
SqlTestFactory.INSTANCE.withValidator(
-        (opTab, catalogReader, typeFactory, conformance) ->
+        (opTab, catalogReader, typeFactory, config) ->
             (SqlValidator) Proxy.newProxyInstance(
                 SqlValidatorSpooler.class.getClassLoader(),
                 new Class[]{SqlValidator.class},
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java 
b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index c79019c..e7b5028 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -81,7 +81,7 @@ import java.util.Objects;
 import java.util.function.Function;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
  * SqlToRelTestBase is an abstract base for tests which involve conversion from
@@ -609,7 +609,8 @@ public abstract class SqlToRelTestBase {
               catalogReader, typeFactory);
       final CalciteConnectionConfig calciteConfig = 
context.unwrap(CalciteConnectionConfig.class);
       if (calciteConfig != null) {
-        
validator.setDefaultNullCollation(calciteConfig.defaultNullCollation());
+        validator.transform(config ->
+            
config.withDefaultNullCollation(calciteConfig.defaultNullCollation()));
       }
       if (config == SqlToRelConverter.Config.DEFAULT) {
         localConfig = SqlToRelConverter.configBuilder()
@@ -690,15 +691,14 @@ public abstract class SqlToRelTestBase {
     public SqlValidator createValidator(
         SqlValidatorCatalogReader catalogReader,
         RelDataTypeFactory typeFactory) {
-      final SqlValidator validator = new FarragoTestValidator(
+      return new FarragoTestValidator(
           getOperatorTable(),
           catalogReader,
           typeFactory,
-          getConformance());
-      // the connection config may be null, set up the flag
-      // separately.
-      validator.setEnableTypeCoercion(enableTypeCoercion);
-      return validator;
+          SqlValidator.Config.DEFAULT
+              .withSqlConformance(conformance)
+              .withTypeCoercionEnabled(enableTypeCoercion)
+              .withIdentifierExpansion(true));
     }
 
     public final SqlOperatorTable getOperatorTable() {
@@ -748,7 +748,7 @@ public abstract class SqlToRelTestBase {
       String sql2 = getDiffRepos().expand("sql", sql);
       RelNode rel = convertSqlToRel(sql2).project();
 
-      assertTrue(rel != null);
+      assertNotNull(rel);
       assertValid(rel);
 
       if (trim) {
@@ -756,7 +756,7 @@ public abstract class SqlToRelTestBase {
             RelFactories.LOGICAL_BUILDER.create(rel.getCluster(), null);
         final RelFieldTrimmer trimmer = createFieldTrimmer(relBuilder);
         rel = trimmer.trim(rel);
-        assertTrue(rel != null);
+        assertNotNull(rel);
         assertValid(rel);
       }
 
@@ -871,13 +871,8 @@ public abstract class SqlToRelTestBase {
         SqlOperatorTable opTab,
         SqlValidatorCatalogReader catalogReader,
         RelDataTypeFactory typeFactory,
-        SqlConformance conformance) {
-      super(opTab, catalogReader, typeFactory, conformance);
-    }
-
-    // override SqlValidator
-    public boolean shouldExpandIdentifiers() {
-      return true;
+        Config config) {
+      super(opTab, catalogReader, typeFactory, config);
     }
   }
 
diff --git 
a/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
index 199fed9..edd0cb2 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
@@ -25,7 +25,6 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.test.SqlTestFactory;
 import org.apache.calcite.sql.test.SqlTester;
 import org.apache.calcite.sql.test.SqlValidatorTester;
-import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
 
@@ -114,8 +113,8 @@ class SqlValidatorFeatureTest extends SqlValidatorTestCase {
         SqlOperatorTable opTab,
         SqlValidatorCatalogReader catalogReader,
         RelDataTypeFactory typeFactory,
-        SqlConformance conformance) {
-      super(opTab, catalogReader, typeFactory, conformance);
+        Config config) {
+      super(opTab, catalogReader, typeFactory, config);
     }
 
     protected void validateFeature(
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index b6f9115..28b37d2 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -8368,7 +8368,7 @@ class SqlValidatorTest extends SqlValidatorTestCase {
         + "FROM `EMP`";
     sql(sql)
         .withValidatorCallRewrite(false)
-        .rewritesTo(tester.getValidator().shouldExpandIdentifiers()
+        .rewritesTo(tester.getValidator().config().identifierExpansion()
             ? expected1 : expected2);
   }
 
@@ -8382,7 +8382,7 @@ class SqlValidatorTest extends SqlValidatorTestCase {
         + "FROM `EMP`";
     sql(sql)
         .withValidatorCallRewrite(true)
-        .rewritesTo(tester.getValidator().shouldExpandIdentifiers()
+        .rewritesTo(tester.getValidator().config().identifierExpansion()
             ? expected1 : expected2);
   }
 
diff --git 
a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
index 3c5e7e9..c8494b3 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
@@ -428,26 +428,20 @@ public class SqlValidatorTestCase {
     }
 
     public Sql withValidatorIdentifierExpansion(boolean expansion) {
-      final UnaryOperator<SqlValidator> after = sqlValidator -> {
-        sqlValidator.setIdentifierExpansion(expansion);
-        return sqlValidator;
-      };
+      final UnaryOperator<SqlValidator> after = sqlValidator ->
+          sqlValidator.transform(config -> 
config.withIdentifierExpansion(expansion));
       return withTester(tester -> addTransform(tester, after));
     }
 
     public Sql withValidatorCallRewrite(boolean rewrite) {
-      final UnaryOperator<SqlValidator> after = sqlValidator -> {
-        sqlValidator.setCallRewrite(rewrite);
-        return sqlValidator;
-      };
+      final UnaryOperator<SqlValidator> after = sqlValidator ->
+          sqlValidator.transform(config -> config.withCallRewrite(rewrite));
       return withTester(tester -> addTransform(tester, after));
     }
 
     public Sql withValidatorColumnReferenceExpansion(boolean expansion) {
-      final UnaryOperator<SqlValidator> after = sqlValidator -> {
-        sqlValidator.setColumnReferenceExpansion(expansion);
-        return sqlValidator;
-      };
+      final UnaryOperator<SqlValidator> after = sqlValidator ->
+          sqlValidator.transform(config -> 
config.withColumnReferenceExpansion(expansion));
       return withTester(tester -> addTransform(tester, after));
     }
 

Reply via email to