You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2018/11/15 12:56:42 UTC
[kylin] branch master updated: KYLIN-3676 Update customized Calctie
This is an automated email from the ASF dual-hosted git repository.
shaofengshi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/master by this push:
new 6344986 KYLIN-3676 Update customized Calctie
6344986 is described below
commit 634498649f20ce61fcabe0b46fe515bb6ca96af0
Author: Lijun Cao <64...@qq.com>
AuthorDate: Mon Nov 12 14:22:49 2018 +0800
KYLIN-3676 Update customized Calctie
---
.../.settings/org.eclipse.core.resources.prefs | 6 -
atopcalcite/.settings/org.eclipse.jdt.core.prefs | 386 --
atopcalcite/.settings/org.eclipse.jdt.ui.prefs | 7 -
atopcalcite/pom.xml | 56 -
.../adapter/enumerable/EnumerableWindowBridge.java | 39 -
.../apache/calcite/prepare/CalcitePrepareImpl.java | 1518 ------
.../prepare/OnlyPrepareEarlyAbortException.java | 40 -
.../apache/calcite/rel/rules/FilterJoinRule.java | 311 --
.../rel/rules/OLAPJoinPushThroughJoinRule.java | 172 -
.../rel/rules/OLAPJoinPushThroughJoinRule2.java | 205 -
.../org/apache/calcite/runtime/SqlFunctions.java | 2238 --------
.../org/apache/calcite/sql/type/SqlTypeUtil.java | 1336 -----
.../apache/calcite/sql2rel/RelFieldTrimmer.java | 45 -
.../apache/calcite/sql2rel/SqlToRelConverter.java | 5656 --------------------
.../java/org/apache/calcite/tools/Programs.java | 438 --
.../java/org/apache/calcite/tools/RelUtils.java | 71 -
.../apache/calcite/runtime/SqlFunctionsTest.java | 38 -
.../apache/kylin/cube/CubeCapabilityChecker.java | 13 +
core-metadata/pom.xml | 15 +-
.../apache/kylin/metadata/model/FunctionDesc.java | 1 +
.../storage/gtrecord/GTCubeStorageQueryBase.java | 2 +-
kylin-it/pom.xml | 15 +-
pom.xml | 3 +-
query/pom.xml | 15 +-
.../query/optrule/AggregateMultipleExpandRule.java | 17 -
.../kylin/query/relnode/OLAPAggregateRel.java | 9 +-
.../relnode/visitor/TupleExpressionVisitor.java | 5 +-
27 files changed, 64 insertions(+), 12593 deletions(-)
diff --git a/atopcalcite/.settings/org.eclipse.core.resources.prefs b/atopcalcite/.settings/org.eclipse.core.resources.prefs
deleted file mode 100644
index 29abf99..0000000
--- a/atopcalcite/.settings/org.eclipse.core.resources.prefs
+++ /dev/null
@@ -1,6 +0,0 @@
-eclipse.preferences.version=1
-encoding//src/main/java=UTF-8
-encoding//src/main/resources=UTF-8
-encoding//src/test/java=UTF-8
-encoding//src/test/resources=UTF-8
-encoding/<project>=UTF-8
diff --git a/atopcalcite/.settings/org.eclipse.jdt.core.prefs b/atopcalcite/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 500de29..0000000
--- a/atopcalcite/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,386 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
-org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
-org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
-org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
-org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
-org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
-org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
-org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
-org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
-org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
-org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.7
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
-org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
-org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_package=1
-org.eclipse.jdt.core.formatter.blank_lines_before_field=0
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=false
-org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=80
-org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
-org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
-org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
-org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=2
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
-org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
-org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
-org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
-org.eclipse.jdt.core.formatter.indentation.size=4
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=true
-org.eclipse.jdt.core.formatter.join_wrapped_lines=true
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=120
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-org.eclipse.jdt.core.formatter.use_on_off_tags=false
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/atopcalcite/.settings/org.eclipse.jdt.ui.prefs b/atopcalcite/.settings/org.eclipse.jdt.ui.prefs
deleted file mode 100644
index d521bab..0000000
--- a/atopcalcite/.settings/org.eclipse.jdt.ui.prefs
+++ /dev/null
@@ -1,7 +0,0 @@
-eclipse.preferences.version=1
-formatter_profile=_Space Indent & Long Lines
-formatter_settings_version=12
-org.eclipse.jdt.ui.ignorelowercasenames=true
-org.eclipse.jdt.ui.importorder=java;javax;org;com;
-org.eclipse.jdt.ui.ondemandthreshold=99
-org.eclipse.jdt.ui.staticondemandthreshold=99
diff --git a/atopcalcite/pom.xml b/atopcalcite/pom.xml
deleted file mode 100644
index 58e40ef..0000000
--- a/atopcalcite/pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>atopcalcite</artifactId>
- <packaging>jar</packaging>
- <name>Apache Kylin - Calcite Overrides</name>
- <description>Apache Kylin - Calcite Overrides</description>
-
- <parent>
- <groupId>org.apache.kylin</groupId>
- <artifactId>kylin</artifactId>
- <version>2.6.0-SNAPSHOT</version>
- </parent>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.calcite</groupId>
- <artifactId>calcite-core</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.apache.calcite.avatica</groupId>
- <artifactId>avatica-core</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- It should be avatica(the shaded one), not avatica-core, since the inconsistency protobuf dependency with Hadoop -->
- <dependency>
- <groupId>org.apache.calcite.avatica</groupId>
- <artifactId>avatica</artifactId>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-</project>
diff --git a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java
deleted file mode 100644
index 13a33e3..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-package org.apache.calcite.adapter.enumerable;
-
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Window;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rex.RexLiteral;
-
-import java.util.List;
-
-/**
- * EnumerableWindow cant'be created out of package, here's hack of workaround
- */
-public class EnumerableWindowBridge {
-
- public static EnumerableWindow createEnumerableWindow(RelOptCluster cluster, RelTraitSet traits, RelNode child,
- List<RexLiteral> constants, RelDataType rowType, List<Window.Group> groups) {
- return new EnumerableWindow(cluster, traits, child, constants, rowType, groups);
- }
-}
diff --git a/atopcalcite/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/atopcalcite/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
deleted file mode 100644
index b63beee..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ /dev/null
@@ -1,1518 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-package org.apache.calcite.prepare;
-
-import static org.apache.calcite.util.Static.RESOURCE;
-
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.sql.DatabaseMetaData;
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.calcite.DataContext;
-import org.apache.calcite.adapter.enumerable.EnumerableBindable;
-import org.apache.calcite.adapter.enumerable.EnumerableCalc;
-import org.apache.calcite.adapter.enumerable.EnumerableConvention;
-import org.apache.calcite.adapter.enumerable.EnumerableInterpretable;
-import org.apache.calcite.adapter.enumerable.EnumerableInterpreterRule;
-import org.apache.calcite.adapter.enumerable.EnumerableRel;
-import org.apache.calcite.adapter.enumerable.EnumerableRules;
-import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.avatica.AvaticaParameter;
-import org.apache.calcite.avatica.ColumnMetaData;
-import org.apache.calcite.avatica.Meta;
-import org.apache.calcite.config.CalciteConnectionConfig;
-import org.apache.calcite.interpreter.BindableConvention;
-import org.apache.calcite.interpreter.Bindables;
-import org.apache.calcite.interpreter.Interpreters;
-import org.apache.calcite.jdbc.CalcitePrepare;
-import org.apache.calcite.jdbc.CalciteSchema;
-import org.apache.calcite.jdbc.CalciteSchema.LatticeEntry;
-import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.linq4j.Linq4j;
-import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.linq4j.Queryable;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.tree.BinaryExpression;
-import org.apache.calcite.linq4j.tree.BlockStatement;
-import org.apache.calcite.linq4j.tree.Blocks;
-import org.apache.calcite.linq4j.tree.ConstantExpression;
-import org.apache.calcite.linq4j.tree.Expression;
-import org.apache.calcite.linq4j.tree.Expressions;
-import org.apache.calcite.linq4j.tree.MemberExpression;
-import org.apache.calcite.linq4j.tree.MethodCallExpression;
-import org.apache.calcite.linq4j.tree.NewExpression;
-import org.apache.calcite.linq4j.tree.ParameterExpression;
-import org.apache.calcite.materialize.MaterializationService;
-import org.apache.calcite.plan.Contexts;
-import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.ConventionTraitDef;
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptCostFactory;
-import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.plan.hep.HepPlanner;
-import org.apache.calcite.plan.hep.HepProgramBuilder;
-import org.apache.calcite.plan.volcano.VolcanoPlanner;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.RelRoot;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rel.rules.AbstractMaterializedViewRule;
-import org.apache.calcite.rel.rules.AggregateExpandDistinctAggregatesRule;
-import org.apache.calcite.rel.rules.AggregateReduceFunctionsRule;
-import org.apache.calcite.rel.rules.AggregateStarTableRule;
-import org.apache.calcite.rel.rules.AggregateValuesRule;
-import org.apache.calcite.rel.rules.FilterAggregateTransposeRule;
-import org.apache.calcite.rel.rules.FilterJoinRule;
-import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
-import org.apache.calcite.rel.rules.FilterTableScanRule;
-import org.apache.calcite.rel.rules.JoinAssociateRule;
-import org.apache.calcite.rel.rules.JoinCommuteRule;
-import org.apache.calcite.rel.rules.JoinPushExpressionsRule;
-import org.apache.calcite.rel.rules.JoinPushThroughJoinRule;
-import org.apache.calcite.rel.rules.MaterializedViewFilterScanRule;
-import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
-import org.apache.calcite.rel.rules.ProjectMergeRule;
-import org.apache.calcite.rel.rules.ProjectTableScanRule;
-import org.apache.calcite.rel.rules.ProjectWindowTransposeRule;
-import org.apache.calcite.rel.rules.ReduceExpressionsRule;
-import org.apache.calcite.rel.rules.SortJoinTransposeRule;
-import org.apache.calcite.rel.rules.SortProjectTransposeRule;
-import org.apache.calcite.rel.rules.SortUnionTransposeRule;
-import org.apache.calcite.rel.rules.TableScanRule;
-import org.apache.calcite.rel.rules.ValuesReduceRule;
-import org.apache.calcite.rel.stream.StreamRules;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexInputRef;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.runtime.Bindable;
-import org.apache.calcite.runtime.Hook;
-import org.apache.calcite.runtime.Typed;
-import org.apache.calcite.schema.Schemas;
-import org.apache.calcite.schema.Table;
-import org.apache.calcite.server.CalciteServerStatement;
-import org.apache.calcite.sql.SqlBinaryOperator;
-import org.apache.calcite.sql.SqlExecutableStatement;
-import org.apache.calcite.sql.SqlExplainFormat;
-import org.apache.calcite.sql.SqlExplainLevel;
-import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlOperator;
-import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.SqlUtil;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.parser.SqlParseException;
-import org.apache.calcite.sql.parser.SqlParser;
-import org.apache.calcite.sql.parser.SqlParserImplFactory;
-import org.apache.calcite.sql.type.SqlTypeName;
-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.SqlRexConvertletTable;
-import org.apache.calcite.sql2rel.SqlToRelConverter;
-import org.apache.calcite.sql2rel.StandardConvertletTable;
-import org.apache.calcite.tools.Frameworks;
-import org.apache.calcite.tools.RelUtils;
-import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Util;
-
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-
-/*
- * OVERRIDE POINT:
- * - grep KYLIN_ONLY_PREPARE
- */
-
-/**
- * Shit just got real.
- *
- * <p>This class is public so that projects that create their own JDBC driver
- * and server can fine-tune preferences. However, this class and its methods are
- * subject to change without notice.</p>
- */
-public class CalcitePrepareImpl implements CalcitePrepare {
-
- public static final ThreadLocal<Boolean> KYLIN_ONLY_PREPARE = new ThreadLocal<>();
-
- public static final boolean DEBUG = Util.getBooleanProperty("calcite.debug");
-
- public static final boolean COMMUTE =
- Util.getBooleanProperty("calcite.enable.join.commute");
-
- /** Whether to enable the collation trait. Some extra optimizations are
- * possible if enabled, but queries should work either way. At some point
- * this will become a preference, or we will run multiple phases: first
- * disabled, then enabled. */
- private static final boolean ENABLE_COLLATION_TRAIT = true;
-
- /** Whether the bindable convention should be the root convention of any
- * plan. If not, enumerable convention is the default. */
- public final boolean enableBindable = Hook.ENABLE_BINDABLE.get(false);
-
- /** Whether the enumerable convention is enabled. */
- public static final boolean ENABLE_ENUMERABLE = true;
-
- /** Whether the streaming is enabled. */
- public static final boolean ENABLE_STREAM = true;
-
- private static final Set<String> SIMPLE_SQLS =
- ImmutableSet.of(
- "SELECT 1",
- "select 1",
- "SELECT 1 FROM DUAL",
- "select 1 from dual",
- "values 1",
- "VALUES 1");
-
- public static final List<RelOptRule> ENUMERABLE_RULES =
- ImmutableList.of(
- EnumerableRules.ENUMERABLE_JOIN_RULE,
- EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE,
- EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
- EnumerableRules.ENUMERABLE_CORRELATE_RULE,
- EnumerableRules.ENUMERABLE_PROJECT_RULE,
- EnumerableRules.ENUMERABLE_FILTER_RULE,
- EnumerableRules.ENUMERABLE_AGGREGATE_RULE,
- EnumerableRules.ENUMERABLE_SORT_RULE,
- EnumerableRules.ENUMERABLE_LIMIT_RULE,
- EnumerableRules.ENUMERABLE_COLLECT_RULE,
- EnumerableRules.ENUMERABLE_UNCOLLECT_RULE,
- EnumerableRules.ENUMERABLE_UNION_RULE,
- EnumerableRules.ENUMERABLE_INTERSECT_RULE,
- EnumerableRules.ENUMERABLE_MINUS_RULE,
- EnumerableRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
- EnumerableRules.ENUMERABLE_VALUES_RULE,
- EnumerableRules.ENUMERABLE_WINDOW_RULE,
- EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE,
- EnumerableRules.ENUMERABLE_TABLE_FUNCTION_SCAN_RULE);
-
- private static final List<RelOptRule> DEFAULT_RULES =
- ImmutableList.of(
- AggregateStarTableRule.INSTANCE,
- AggregateStarTableRule.INSTANCE2,
- TableScanRule.INSTANCE,
- COMMUTE
- ? JoinAssociateRule.INSTANCE
- : ProjectMergeRule.INSTANCE,
- FilterTableScanRule.INSTANCE,
- ProjectFilterTransposeRule.INSTANCE,
- FilterProjectTransposeRule.INSTANCE,
- FilterJoinRule.FILTER_ON_JOIN,
- JoinPushExpressionsRule.INSTANCE,
- AggregateExpandDistinctAggregatesRule.INSTANCE,
- AggregateReduceFunctionsRule.INSTANCE,
- FilterAggregateTransposeRule.INSTANCE,
- ProjectWindowTransposeRule.INSTANCE,
- JoinCommuteRule.INSTANCE,
- JoinPushThroughJoinRule.RIGHT,
- JoinPushThroughJoinRule.LEFT,
- SortProjectTransposeRule.INSTANCE,
- SortJoinTransposeRule.INSTANCE,
- SortUnionTransposeRule.INSTANCE);
-
- private static final List<RelOptRule> CONSTANT_REDUCTION_RULES =
- ImmutableList.of(
- ReduceExpressionsRule.PROJECT_INSTANCE,
- ReduceExpressionsRule.FILTER_INSTANCE,
- ReduceExpressionsRule.CALC_INSTANCE,
- ReduceExpressionsRule.JOIN_INSTANCE,
- ValuesReduceRule.FILTER_INSTANCE,
- ValuesReduceRule.PROJECT_FILTER_INSTANCE,
- ValuesReduceRule.PROJECT_INSTANCE,
- AggregateValuesRule.INSTANCE);
-
- public CalcitePrepareImpl() {
- }
-
- public ParseResult parse(
- Context context, String sql) {
- return parse_(context, sql, false, false, false);
- }
-
- public ConvertResult convert(Context context, String sql) {
- return (ConvertResult) parse_(context, sql, true, false, false);
- }
-
- public AnalyzeViewResult analyzeView(Context context, String sql, boolean fail) {
- return (AnalyzeViewResult) parse_(context, sql, true, true, fail);
- }
-
- /** Shared implementation for {@link #parse}, {@link #convert} and
- * {@link #analyzeView}. */
- private ParseResult parse_(Context context, String sql, boolean convert,
- boolean analyze, boolean fail) {
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- CalciteCatalogReader catalogReader =
- new CalciteCatalogReader(
- context.getRootSchema(),
- context.config().caseSensitive(),
- context.getDefaultSchemaPath(),
- typeFactory);
- SqlParser parser = createParser(sql);
- SqlNode sqlNode;
- try {
- sqlNode = parser.parseStmt();
- } catch (SqlParseException e) {
- throw new RuntimeException("parse failed", e);
- }
- final SqlValidator validator = createSqlValidator(context, catalogReader);
- SqlNode sqlNode1 = validator.validate(sqlNode);
- if (convert) {
- return convert_(
- context, sql, analyze, fail, catalogReader, validator, sqlNode1);
- }
- return new ParseResult(this, validator, sql, sqlNode1,
- validator.getValidatedNodeType(sqlNode1));
- }
-
- private ParseResult convert_(Context context, String sql, boolean analyze,
- boolean fail, CalciteCatalogReader catalogReader, SqlValidator validator,
- SqlNode sqlNode1) {
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- final Convention resultConvention =
- enableBindable ? BindableConvention.INSTANCE
- : EnumerableConvention.INSTANCE;
- final HepPlanner planner = new HepPlanner(new HepProgramBuilder().build());
- planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
-
- final SqlToRelConverter.ConfigBuilder configBuilder =
- SqlToRelConverter.configBuilder().withTrimUnusedFields(true);
- if (analyze) {
- configBuilder.withConvertTableAccess(false);
- }
-
- final CalcitePreparingStmt preparingStmt =
- new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
- context.getRootSchema(), null, planner, resultConvention,
- createConvertletTable());
- final SqlToRelConverter converter =
- preparingStmt.getSqlToRelConverter(validator, catalogReader,
- configBuilder.build());
-
- final RelRoot root = converter.convertQuery(sqlNode1, false, true);
- if (analyze) {
- return analyze_(validator, sql, sqlNode1, root, fail);
- }
- return new ConvertResult(this, validator, sql, sqlNode1,
- validator.getValidatedNodeType(sqlNode1), root);
- }
-
- private AnalyzeViewResult analyze_(SqlValidator validator, String sql,
- SqlNode sqlNode, RelRoot root, boolean fail) {
- final RexBuilder rexBuilder = root.rel.getCluster().getRexBuilder();
- RelNode rel = root.rel;
- final RelNode viewRel = rel;
- Project project;
- if (rel instanceof Project) {
- project = (Project) rel;
- rel = project.getInput();
- } else {
- project = null;
- }
- Filter filter;
- if (rel instanceof Filter) {
- filter = (Filter) rel;
- rel = filter.getInput();
- } else {
- filter = null;
- }
- TableScan scan;
- if (rel instanceof TableScan) {
- scan = (TableScan) rel;
- } else {
- scan = null;
- }
- if (scan == null) {
- if (fail) {
- throw validator.newValidationError(sqlNode,
- RESOURCE.modifiableViewMustBeBasedOnSingleTable());
- }
- return new AnalyzeViewResult(this, validator, sql, sqlNode,
- validator.getValidatedNodeType(sqlNode), root, null, null, null,
- null, false);
- }
- final RelOptTable targetRelTable = scan.getTable();
- final RelDataType targetRowType = targetRelTable.getRowType();
- final Table table = targetRelTable.unwrap(Table.class);
- final List<String> tablePath = targetRelTable.getQualifiedName();
- assert table != null;
- List<Integer> columnMapping;
- final Map<Integer, RexNode> projectMap = new HashMap<>();
- if (project == null) {
- columnMapping = ImmutableIntList.range(0, targetRowType.getFieldCount());
- } else {
- columnMapping = new ArrayList<>();
- for (Ord<RexNode> node : Ord.zip(project.getProjects())) {
- if (node.e instanceof RexInputRef) {
- RexInputRef rexInputRef = (RexInputRef) node.e;
- int index = rexInputRef.getIndex();
- if (projectMap.get(index) != null) {
- if (fail) {
- throw validator.newValidationError(sqlNode,
- RESOURCE.moreThanOneMappedColumn(
- targetRowType.getFieldList().get(index).getName(),
- Util.last(tablePath)));
- }
- return new AnalyzeViewResult(this, validator, sql, sqlNode,
- validator.getValidatedNodeType(sqlNode), root, null, null, null,
- null, false);
- }
- projectMap.put(index, rexBuilder.makeInputRef(viewRel, node.i));
- columnMapping.add(index);
- } else {
- columnMapping.add(-1);
- }
- }
- }
- final RexNode constraint;
- if (filter != null) {
- constraint = filter.getCondition();
- } else {
- constraint = rexBuilder.makeLiteral(true);
- }
- final List<RexNode> filters = new ArrayList<>();
- // If we put a constraint in projectMap above, then filters will not be empty despite
- // being a modifiable view.
- final List<RexNode> filters2 = new ArrayList<>();
- boolean retry = false;
- RelOptUtil.inferViewPredicates(projectMap, filters, constraint);
- if (fail && !filters.isEmpty()) {
- final Map<Integer, RexNode> projectMap2 = new HashMap<>();
- RelOptUtil.inferViewPredicates(projectMap2, filters2, constraint);
- if (!filters2.isEmpty()) {
- throw validator.newValidationError(sqlNode,
- RESOURCE.modifiableViewMustHaveOnlyEqualityPredicates());
- }
- retry = true;
- }
-
- // Check that all columns that are not projected have a constant value
- for (RelDataTypeField field : targetRowType.getFieldList()) {
- final int x = columnMapping.indexOf(field.getIndex());
- if (x >= 0) {
- assert Util.skip(columnMapping, x + 1).indexOf(field.getIndex()) < 0
- : "column projected more than once; should have checked above";
- continue; // target column is projected
- }
- if (projectMap.get(field.getIndex()) != null) {
- continue; // constant expression
- }
- if (field.getType().isNullable()) {
- continue; // don't need expression for nullable columns; NULL suffices
- }
- if (fail) {
- throw validator.newValidationError(sqlNode,
- RESOURCE.noValueSuppliedForViewColumn(field.getName(),
- Util.last(tablePath)));
- }
- return new AnalyzeViewResult(this, validator, sql, sqlNode,
- validator.getValidatedNodeType(sqlNode), root, null, null, null,
- null, false);
- }
-
- final boolean modifiable = filters.isEmpty() || retry && filters2.isEmpty();
- return new AnalyzeViewResult(this, validator, sql, sqlNode,
- validator.getValidatedNodeType(sqlNode), root, modifiable ? table : null,
- ImmutableList.copyOf(tablePath),
- constraint, ImmutableIntList.copyOf(columnMapping),
- modifiable);
- }
-
- @Override public void executeDdl(Context context, SqlNode node) {
- if (node instanceof SqlExecutableStatement) {
- SqlExecutableStatement statement = (SqlExecutableStatement) node;
- statement.execute(context);
- return;
- }
- throw new UnsupportedOperationException();
- }
-
- /** Factory method for default SQL parser. */
- protected SqlParser createParser(String sql) {
- return createParser(sql, createParserConfig());
- }
-
- /** Factory method for SQL parser with a given configuration. */
- protected SqlParser createParser(String sql,
- SqlParser.ConfigBuilder parserConfig) {
- return SqlParser.create(sql, parserConfig.build());
- }
-
- /** Factory method for SQL parser configuration. */
- protected SqlParser.ConfigBuilder createParserConfig() {
- return SqlParser.configBuilder();
- }
-
- /** Factory method for default convertlet table. */
- protected SqlRexConvertletTable createConvertletTable() {
- return StandardConvertletTable.INSTANCE;
- }
-
- /** Factory method for cluster. */
- protected RelOptCluster createCluster(RelOptPlanner planner,
- RexBuilder rexBuilder) {
- return RelOptCluster.create(planner, rexBuilder);
- }
-
- /** Creates a collection of planner factories.
- *
- * <p>The collection must have at least one factory, and each factory must
- * create a planner. If the collection has more than one planner, Calcite will
- * try each planner in turn.</p>
- *
- * <p>One of the things you can do with this mechanism is to try a simpler,
- * faster, planner with a smaller rule set first, then fall back to a more
- * complex planner for complex and costly queries.</p>
- *
- * <p>The default implementation returns a factory that calls
- * {@link #createPlanner(org.apache.calcite.jdbc.CalcitePrepare.Context)}.</p>
- */
- protected List<Function1<Context, RelOptPlanner>> createPlannerFactories() {
- return Collections.<Function1<Context, RelOptPlanner>>singletonList(
- new Function1<Context, RelOptPlanner>() {
- public RelOptPlanner apply(Context context) {
- return createPlanner(context, null, null);
- }
- });
- }
-
- /** Creates a query planner and initializes it with a default set of
- * rules. */
- protected RelOptPlanner createPlanner(CalcitePrepare.Context prepareContext) {
- return createPlanner(prepareContext, null, null);
- }
-
- /** Creates a query planner and initializes it with a default set of
- * rules. */
- protected RelOptPlanner createPlanner(
- final CalcitePrepare.Context prepareContext,
- org.apache.calcite.plan.Context externalContext,
- RelOptCostFactory costFactory) {
- if (externalContext == null) {
- externalContext = Contexts.of(prepareContext.config());
- }
- final VolcanoPlanner planner =
- new VolcanoPlanner(costFactory, externalContext);
- planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
- if (ENABLE_COLLATION_TRAIT) {
- planner.addRelTraitDef(RelCollationTraitDef.INSTANCE);
- planner.registerAbstractRelationalRules();
- }
- RelOptUtil.registerAbstractRels(planner);
- for (RelOptRule rule : DEFAULT_RULES) {
- planner.addRule(rule);
- }
- if (prepareContext.config().materializationsEnabled()) {
- planner.addRule(MaterializedViewFilterScanRule.INSTANCE);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_PROJECT_FILTER);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_FILTER);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_PROJECT_JOIN);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_JOIN);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_PROJECT_AGGREGATE);
- planner.addRule(AbstractMaterializedViewRule.INSTANCE_AGGREGATE);
- }
- if (enableBindable) {
- for (RelOptRule rule : Bindables.RULES) {
- planner.addRule(rule);
- }
- }
- planner.addRule(Bindables.BINDABLE_TABLE_SCAN_RULE);
- planner.addRule(ProjectTableScanRule.INSTANCE);
- planner.addRule(ProjectTableScanRule.INTERPRETER);
-
- if (ENABLE_ENUMERABLE) {
- for (RelOptRule rule : ENUMERABLE_RULES) {
- planner.addRule(rule);
- }
- planner.addRule(EnumerableInterpreterRule.INSTANCE);
- }
-
- if (enableBindable && ENABLE_ENUMERABLE) {
- planner.addRule(
- EnumerableBindable.EnumerableToBindableConverterRule.INSTANCE);
- }
-
- if (ENABLE_STREAM) {
- for (RelOptRule rule : StreamRules.RULES) {
- planner.addRule(rule);
- }
- }
-
- // Change the below to enable constant-reduction.
- if (false) {
- for (RelOptRule rule : CONSTANT_REDUCTION_RULES) {
- planner.addRule(rule);
- }
- }
-
- final SparkHandler spark = prepareContext.spark();
- if (spark.enabled()) {
- spark.registerRules(
- new SparkHandler.RuleSetBuilder() {
- public void addRule(RelOptRule rule) {
- // TODO:
- }
-
- public void removeRule(RelOptRule rule) {
- // TODO:
- }
- });
- }
-
- Hook.PLANNER.run(planner); // allow test to add or remove rules
-
- return planner;
- }
-
- public <T> CalciteSignature<T> prepareQueryable(
- Context context,
- Queryable<T> queryable) {
- return prepare_(context, Query.of(queryable), queryable.getElementType(),
- -1);
- }
-
- public <T> CalciteSignature<T> prepareSql(
- Context context,
- Query<T> query,
- Type elementType,
- long maxRowCount) {
- return prepare_(context, query, elementType, maxRowCount);
- }
-
- <T> CalciteSignature<T> prepare_(
- Context context,
- Query<T> query,
- Type elementType,
- long maxRowCount) {
- if (SIMPLE_SQLS.contains(query.sql)) {
- return simplePrepare(context, query.sql);
- }
-
- if(KYLIN_ONLY_PREPARE.get() != null && KYLIN_ONLY_PREPARE.get()) {
- ParseResult parseResult = parse(context, query.sql);
- Class<OnlyPrepareEarlyAbortException> onlyPrepareEarlyAbortExceptionClass =
- OnlyPrepareEarlyAbortException.class;
- throw new OnlyPrepareEarlyAbortException(context, parseResult);
- }
-
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- CalciteCatalogReader catalogReader =
- new CalciteCatalogReader(
- context.getRootSchema(),
- context.config().caseSensitive(),
- context.getDefaultSchemaPath(),
- typeFactory);
- final List<Function1<Context, RelOptPlanner>> plannerFactories =
- createPlannerFactories();
- if (plannerFactories.isEmpty()) {
- throw new AssertionError("no planner factories");
- }
- RuntimeException exception = Util.FoundOne.NULL;
- for (Function1<Context, RelOptPlanner> plannerFactory : plannerFactories) {
- final RelOptPlanner planner = plannerFactory.apply(context);
- if (planner == null) {
- throw new AssertionError("factory returned null planner");
- }
- try {
- return prepare2_(context, query, elementType, maxRowCount,
- catalogReader, planner);
- } catch (RelOptPlanner.CannotPlanException e) {
- exception = e;
- }
- }
- throw exception;
- }
-
- /** Quickly prepares a simple SQL statement, circumventing the usual
- * preparation process. */
- private <T> CalciteSignature<T> simplePrepare(Context context, String sql) {
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- final RelDataType x =
- typeFactory.builder()
- .add(SqlUtil.deriveAliasFromOrdinal(0), SqlTypeName.INTEGER)
- .build();
- @SuppressWarnings("unchecked")
- final List<T> list = (List) ImmutableList.of(1);
- final List<String> origin = null;
- final List<List<String>> origins =
- Collections.nCopies(x.getFieldCount(), origin);
- final List<ColumnMetaData> columns =
- getColumnMetaDataList(typeFactory, x, x, origins);
- final Meta.CursorFactory cursorFactory =
- Meta.CursorFactory.deduce(columns, null);
- return new CalciteSignature<>(
- sql,
- ImmutableList.<AvaticaParameter>of(),
- ImmutableMap.<String, Object>of(),
- x,
- columns,
- cursorFactory,
- context.getRootSchema(),
- ImmutableList.<RelCollation>of(),
- -1,
- new Bindable<T>() {
- public Enumerable<T> bind(DataContext dataContext) {
- return Linq4j.asEnumerable(list);
- }
- },
- Meta.StatementType.SELECT);
- }
-
- /**
- * Deduces the broad type of statement.
- * Currently returns SELECT for most statement types, but this may change.
- *
- * @param kind Kind of statement
- */
- private Meta.StatementType getStatementType(SqlKind kind) {
- switch (kind) {
- case INSERT:
- case DELETE:
- case UPDATE:
- return Meta.StatementType.IS_DML;
- default:
- return Meta.StatementType.SELECT;
- }
- }
-
- /**
- * Deduces the broad type of statement for a prepare result.
- * Currently returns SELECT for most statement types, but this may change.
- *
- * @param preparedResult Prepare result
- */
- private Meta.StatementType getStatementType(Prepare.PreparedResult preparedResult) {
- if (preparedResult.isDml()) {
- return Meta.StatementType.IS_DML;
- } else {
- return Meta.StatementType.SELECT;
- }
- }
-
- <T> CalciteSignature<T> prepare2_(
- Context context,
- Query<T> query,
- Type elementType,
- long maxRowCount,
- CalciteCatalogReader catalogReader,
- RelOptPlanner planner) {
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- final EnumerableRel.Prefer prefer;
- if (elementType == Object[].class) {
- prefer = EnumerableRel.Prefer.ARRAY;
- } else {
- prefer = EnumerableRel.Prefer.CUSTOM;
- }
- final Convention resultConvention =
- enableBindable ? BindableConvention.INSTANCE
- : EnumerableConvention.INSTANCE;
- final CalcitePreparingStmt preparingStmt =
- new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
- context.getRootSchema(), prefer, planner, resultConvention,
- createConvertletTable());
-
- final RelDataType x;
- final Prepare.PreparedResult preparedResult;
- final Meta.StatementType statementType;
- if (query.sql != null) {
- final CalciteConnectionConfig config = context.config();
- final SqlParser.ConfigBuilder parserConfig = createParserConfig()
- .setQuotedCasing(config.quotedCasing())
- .setUnquotedCasing(config.unquotedCasing())
- .setQuoting(config.quoting())
- .setConformance(config.conformance());
- final SqlParserImplFactory parserFactory =
- config.parserFactory(SqlParserImplFactory.class, null);
- if (parserFactory != null) {
- parserConfig.setParserFactory(parserFactory);
- }
- SqlParser parser = createParser(query.sql, parserConfig);
- SqlNode sqlNode;
- try {
- sqlNode = parser.parseStmt();
- statementType = getStatementType(sqlNode.getKind());
- } catch (SqlParseException e) {
- throw new RuntimeException(
- "parse failed: " + e.getMessage(), e);
- }
-
- Hook.PARSE_TREE.run(new Object[] {query.sql, sqlNode});
-
- if (sqlNode.getKind().belongsTo(SqlKind.DDL)) {
- executeDdl(context, sqlNode);
-
- // Return a dummy signature that contains no rows
- final Bindable<T> bindable = new Bindable<T>() {
- public Enumerable<T> bind(DataContext dataContext) {
- return Linq4j.emptyEnumerable();
- }
- };
- return new CalciteSignature<>(query.sql,
- ImmutableList.<AvaticaParameter>of(),
- ImmutableMap.<String, Object>of(), null,
- ImmutableList.<ColumnMetaData>of(), Meta.CursorFactory.OBJECT,
- null, ImmutableList.<RelCollation>of(), -1, bindable);
- }
-
- final SqlValidator validator =
- createSqlValidator(context, catalogReader);
- validator.setIdentifierExpansion(true);
- validator.setDefaultNullCollation(config.defaultNullCollation());
-
- preparedResult = preparingStmt.prepareSql(
- sqlNode, Object.class, validator, true);
- switch (sqlNode.getKind()) {
- case INSERT:
- case DELETE:
- case UPDATE:
- case EXPLAIN:
- // FIXME: getValidatedNodeType is wrong for DML
- x = RelOptUtil.createDmlRowType(sqlNode.getKind(), typeFactory);
- break;
- default:
- x = validator.getValidatedNodeType(sqlNode);
- }
- } else if (query.queryable != null) {
- x = context.getTypeFactory().createType(elementType);
- preparedResult =
- preparingStmt.prepareQueryable(query.queryable, x);
- statementType = getStatementType(preparedResult);
- } else {
- assert query.rel != null;
- x = query.rel.getRowType();
- preparedResult = preparingStmt.prepareRel(query.rel);
- statementType = getStatementType(preparedResult);
- }
-
- final List<AvaticaParameter> parameters = new ArrayList<>();
- final RelDataType parameterRowType = preparedResult.getParameterRowType();
- for (RelDataTypeField field : parameterRowType.getFieldList()) {
- RelDataType type = field.getType();
- parameters.add(
- new AvaticaParameter(
- false,
- getPrecision(type),
- getScale(type),
- getTypeOrdinal(type),
- getTypeName(type),
- getClassName(type),
- field.getName()));
- }
-
- RelDataType jdbcType = makeStruct(typeFactory, x);
- final List<List<String>> originList = preparedResult.getFieldOrigins();
- final List<ColumnMetaData> columns =
- getColumnMetaDataList(typeFactory, x, jdbcType, originList);
- Class resultClazz = null;
- if (preparedResult instanceof Typed) {
- resultClazz = (Class) ((Typed) preparedResult).getElementType();
- }
- final Meta.CursorFactory cursorFactory =
- preparingStmt.resultConvention == BindableConvention.INSTANCE
- ? Meta.CursorFactory.ARRAY
- : Meta.CursorFactory.deduce(columns, resultClazz);
- //noinspection unchecked
- final Bindable<T> bindable = preparedResult.getBindable(cursorFactory);
- return new CalciteSignature<>(
- query.sql,
- parameters,
- preparingStmt.internalParameters,
- jdbcType,
- columns,
- cursorFactory,
- context.getRootSchema(),
- preparedResult instanceof Prepare.PreparedResultImpl
- ? ((Prepare.PreparedResultImpl) preparedResult).collations
- : ImmutableList.<RelCollation>of(),
- maxRowCount,
- bindable,
- statementType);
- }
-
- private SqlValidator createSqlValidator(Context context,
- CalciteCatalogReader catalogReader) {
- final SqlOperatorTable opTab0 =
- context.config().fun(SqlOperatorTable.class,
- SqlStdOperatorTable.instance());
- final SqlOperatorTable opTab =
- ChainedSqlOperatorTable.of(opTab0, catalogReader);
- final JavaTypeFactory typeFactory = context.getTypeFactory();
- final SqlConformance conformance = context.config().conformance();
- return new CalciteSqlValidator(opTab, catalogReader, typeFactory,
- conformance);
- }
-
- private List<ColumnMetaData> getColumnMetaDataList(
- JavaTypeFactory typeFactory, RelDataType x, RelDataType jdbcType,
- List<List<String>> originList) {
- final List<ColumnMetaData> columns = new ArrayList<>();
- for (Ord<RelDataTypeField> pair : Ord.zip(jdbcType.getFieldList())) {
- final RelDataTypeField field = pair.e;
- final RelDataType type = field.getType();
- final RelDataType fieldType =
- x.isStruct() ? x.getFieldList().get(pair.i).getType() : type;
- columns.add(
- metaData(typeFactory, columns.size(), field.getName(), type,
- fieldType, originList.get(pair.i)));
- }
- return columns;
- }
-
- private ColumnMetaData metaData(JavaTypeFactory typeFactory, int ordinal,
- String fieldName, RelDataType type, RelDataType fieldType,
- List<String> origins) {
- final ColumnMetaData.AvaticaType avaticaType =
- avaticaType(typeFactory, type, fieldType);
- return new ColumnMetaData(
- ordinal,
- false,
- true,
- false,
- false,
- type.isNullable()
- ? DatabaseMetaData.columnNullable
- : DatabaseMetaData.columnNoNulls,
- true,
- type.getPrecision(),
- fieldName,
- origin(origins, 0),
- origin(origins, 2),
- getPrecision(type),
- getScale(type),
- origin(origins, 1),
- null,
- avaticaType,
- true,
- false,
- false,
- avaticaType.columnClassName());
- }
-
- private ColumnMetaData.AvaticaType avaticaType(JavaTypeFactory typeFactory,
- RelDataType type, RelDataType fieldType) {
- final String typeName = getTypeName(type);
- if (type.getComponentType() != null) {
- final ColumnMetaData.AvaticaType componentType =
- avaticaType(typeFactory, type.getComponentType(), null);
- final Type clazz = typeFactory.getJavaClass(type.getComponentType());
- final ColumnMetaData.Rep rep = ColumnMetaData.Rep.of(clazz);
- assert rep != null;
- return ColumnMetaData.array(componentType, typeName, rep);
- } else {
- final int typeOrdinal = getTypeOrdinal(type);
- switch (typeOrdinal) {
- case Types.STRUCT:
- final List<ColumnMetaData> columns = new ArrayList<>();
- for (RelDataTypeField field : type.getFieldList()) {
- columns.add(
- metaData(typeFactory, field.getIndex(), field.getName(),
- field.getType(), null, null));
- }
- return ColumnMetaData.struct(columns);
- default:
- final Type clazz =
- typeFactory.getJavaClass(Util.first(fieldType, type));
- final ColumnMetaData.Rep rep = ColumnMetaData.Rep.of(clazz);
- assert rep != null;
- return ColumnMetaData.scalar(typeOrdinal, typeName, rep);
- }
- }
- }
-
- private static String origin(List<String> origins, int offsetFromEnd) {
- return origins == null || offsetFromEnd >= origins.size()
- ? null
- : origins.get(origins.size() - 1 - offsetFromEnd);
- }
-
- private int getTypeOrdinal(RelDataType type) {
- return type.getSqlTypeName().getJdbcOrdinal();
- }
-
- private static String getClassName(RelDataType type) {
- return null;
- }
-
- private static int getScale(RelDataType type) {
- return type.getScale() == RelDataType.SCALE_NOT_SPECIFIED
- ? 0
- : type.getScale();
- }
-
- private static int getPrecision(RelDataType type) {
- return type.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED
- ? 0
- : type.getPrecision();
- }
-
- /** Returns the type name in string form. Does not include precision, scale
- * or whether nulls are allowed. Example: "DECIMAL" not "DECIMAL(7, 2)";
- * "INTEGER" not "JavaType(int)". */
- private static String getTypeName(RelDataType type) {
- final SqlTypeName sqlTypeName = type.getSqlTypeName();
- switch (sqlTypeName) {
- case ARRAY:
- case MULTISET:
- case MAP:
- case ROW:
- return type.toString(); // e.g. "INTEGER ARRAY"
- case INTERVAL_YEAR_MONTH:
- return "INTERVAL_YEAR_TO_MONTH";
- case INTERVAL_DAY_HOUR:
- return "INTERVAL_DAY_TO_HOUR";
- case INTERVAL_DAY_MINUTE:
- return "INTERVAL_DAY_TO_MINUTE";
- case INTERVAL_DAY_SECOND:
- return "INTERVAL_DAY_TO_SECOND";
- case INTERVAL_HOUR_MINUTE:
- return "INTERVAL_HOUR_TO_MINUTE";
- case INTERVAL_HOUR_SECOND:
- return "INTERVAL_HOUR_TO_SECOND";
- case INTERVAL_MINUTE_SECOND:
- return "INTERVAL_MINUTE_TO_SECOND";
- default:
- return sqlTypeName.getName(); // e.g. "DECIMAL", "INTERVAL_YEAR_MONTH"
- }
- }
-
- protected void populateMaterializations(Context context,
- RelOptPlanner planner, Prepare.Materialization materialization) {
- // REVIEW: initialize queryRel and tableRel inside MaterializationService,
- // not here?
- try {
- final CalciteSchema schema = materialization.materializedTable.schema;
- CalciteCatalogReader catalogReader =
- new CalciteCatalogReader(
- schema.root(),
- context.config().caseSensitive(),
- materialization.viewSchemaPath,
- context.getTypeFactory());
- final CalciteMaterializer materializer =
- new CalciteMaterializer(this, context, catalogReader, schema, planner,
- createConvertletTable());
- materializer.populate(materialization);
- } catch (Exception e) {
- throw new RuntimeException("While populating materialization "
- + materialization.materializedTable.path(), e);
- }
- }
-
- private static RelDataType makeStruct(
- RelDataTypeFactory typeFactory,
- RelDataType type) {
- if (type.isStruct()) {
- return type;
- }
- return typeFactory.builder().add("$0", type).build();
- }
-
- /** Executes a prepare action. */
- public <R> R perform(CalciteServerStatement statement,
- Frameworks.PrepareAction<R> action) {
- final CalcitePrepare.Context prepareContext =
- statement.createPrepareContext();
- final JavaTypeFactory typeFactory = prepareContext.getTypeFactory();
- final CalciteSchema schema =
- action.getConfig().getDefaultSchema() != null
- ? CalciteSchema.from(action.getConfig().getDefaultSchema())
- : prepareContext.getRootSchema();
- CalciteCatalogReader catalogReader =
- new CalciteCatalogReader(schema.root(),
- prepareContext.config().caseSensitive(),
- schema.path(null),
- typeFactory);
- final RexBuilder rexBuilder = new RexBuilder(typeFactory);
- final RelOptPlanner planner =
- createPlanner(prepareContext,
- action.getConfig().getContext(),
- action.getConfig().getCostFactory());
- final RelOptCluster cluster = createCluster(planner, rexBuilder);
- return action.apply(cluster, catalogReader,
- prepareContext.getRootSchema().plus(), statement);
- }
-
- /** Holds state for the process of preparing a SQL statement. */
- static class CalcitePreparingStmt extends Prepare
- implements RelOptTable.ViewExpander {
- protected final RelOptPlanner planner;
- protected final RexBuilder rexBuilder;
- protected final CalcitePrepareImpl prepare;
- protected final CalciteSchema schema;
- protected final RelDataTypeFactory typeFactory;
- protected final SqlRexConvertletTable convertletTable;
- private final EnumerableRel.Prefer prefer;
- private final Map<String, Object> internalParameters =
- Maps.newLinkedHashMap();
- private int expansionDepth;
- private SqlValidator sqlValidator;
-
- public CalcitePreparingStmt(CalcitePrepareImpl prepare,
- Context context,
- CatalogReader catalogReader,
- RelDataTypeFactory typeFactory,
- CalciteSchema schema,
- EnumerableRel.Prefer prefer,
- RelOptPlanner planner,
- Convention resultConvention,
- SqlRexConvertletTable convertletTable) {
- super(context, catalogReader, resultConvention);
- this.prepare = prepare;
- this.schema = schema;
- this.prefer = prefer;
- this.planner = planner;
- this.typeFactory = typeFactory;
- this.convertletTable = convertletTable;
- this.rexBuilder = new RexBuilder(typeFactory);
- }
-
- @Override protected void init(Class runtimeContextClass) {
- }
-
- public PreparedResult prepareQueryable(
- final Queryable queryable,
- RelDataType resultType) {
- return prepare_(
- new Supplier<RelNode>() {
- public RelNode get() {
- final RelOptCluster cluster =
- prepare.createCluster(planner, rexBuilder);
- return new LixToRelTranslator(cluster, CalcitePreparingStmt.this)
- .translate(queryable);
- }
- }, resultType);
- }
-
- public PreparedResult prepareRel(final RelNode rel) {
- return prepare_(
- new Supplier<RelNode>() {
- public RelNode get() {
- return rel;
- }
- }, rel.getRowType());
- }
-
- private PreparedResult prepare_(Supplier<RelNode> fn,
- RelDataType resultType) {
- queryString = null;
- Class runtimeContextClass = Object.class;
- init(runtimeContextClass);
-
- final RelNode rel = fn.get();
- final RelDataType rowType = rel.getRowType();
- final List<Pair<Integer, String>> fields =
- Pair.zip(ImmutableIntList.identity(rowType.getFieldCount()),
- rowType.getFieldNames());
- final RelCollation collation =
- rel instanceof Sort
- ? ((Sort) rel).collation
- : RelCollations.EMPTY;
- RelRoot root = new RelRoot(rel, resultType, SqlKind.SELECT, fields,
- collation);
-
- if (timingTracer != null) {
- timingTracer.traceTime("end sql2rel");
- }
-
- final RelDataType jdbcType =
- makeStruct(rexBuilder.getTypeFactory(), resultType);
- fieldOrigins = Collections.nCopies(jdbcType.getFieldCount(), null);
- parameterRowType = rexBuilder.getTypeFactory().builder().build();
-
- // Structured type flattening, view expansion, and plugging in
- // physical storage.
- root = root.withRel(flattenTypes(root.rel, true));
-
- // Trim unused fields.
- root = trimUnusedFields(root);
-
- final List<Materialization> materializations = ImmutableList.of();
- final List<LatticeEntry> lattices = ImmutableList.of();
- long start = System.currentTimeMillis();
- LOGGER.info("Begin optimize");
- root = optimize(root, materializations, lattices);
- LOGGER.info("End optimize, take : " + (System.currentTimeMillis() - start));
-
- if (timingTracer != null) {
- timingTracer.traceTime("end optimization");
- }
-
- return implement(root);
- }
-
- @Override protected SqlToRelConverter getSqlToRelConverter(
- SqlValidator validator,
- CatalogReader catalogReader,
- SqlToRelConverter.Config config) {
- final RelOptCluster cluster = prepare.createCluster(planner, rexBuilder);
- SqlToRelConverter sqlToRelConverter =
- new SqlToRelConverter(this, validator, catalogReader, cluster,
- convertletTable, config);
- return sqlToRelConverter;
- }
-
- @Override public RelNode flattenTypes(
- RelNode rootRel,
- boolean restructure) {
- final SparkHandler spark = context.spark();
- if (spark.enabled()) {
- return spark.flattenTypes(planner, rootRel, restructure);
- }
- return rootRel;
- }
-
- @Override protected RelNode decorrelate(SqlToRelConverter sqlToRelConverter,
- SqlNode query, RelNode rootRel) {
- return sqlToRelConverter.decorrelate(query, rootRel);
- }
-
- @Override public RelRoot expandView(RelDataType rowType, String queryString,
- List<String> schemaPath, List<String> viewPath) {
- expansionDepth++;
-
- SqlParser parser = prepare.createParser(queryString);
- SqlNode sqlNode;
- try {
- sqlNode = parser.parseQuery();
- } catch (SqlParseException e) {
- throw new RuntimeException("parse failed", e);
- }
- // View may have different schema path than current connection.
- final CatalogReader catalogReader =
- this.catalogReader.withSchemaPath(schemaPath);
- SqlValidator validator = createSqlValidator(catalogReader);
- SqlNode sqlNode1 = validator.validate(sqlNode);
- final SqlToRelConverter.Config config = SqlToRelConverter.configBuilder()
- .withTrimUnusedFields(true).build();
- SqlToRelConverter sqlToRelConverter =
- getSqlToRelConverter(validator, catalogReader, config);
- RelRoot root =
- sqlToRelConverter.convertQuery(sqlNode1, true, false);
-
- --expansionDepth;
- return root;
- }
-
- protected SqlValidator createSqlValidator(CatalogReader catalogReader) {
- return prepare.createSqlValidator(context,
- (CalciteCatalogReader) catalogReader);
- }
-
- @Override protected SqlValidator getSqlValidator() {
- if (sqlValidator == null) {
- sqlValidator = createSqlValidator(catalogReader);
- }
- return sqlValidator;
- }
-
- @Override protected PreparedResult createPreparedExplanation(
- RelDataType resultType,
- RelDataType parameterRowType,
- RelRoot root,
- SqlExplainFormat format,
- SqlExplainLevel detailLevel) {
- return new CalcitePreparedExplain(resultType, parameterRowType, root,
- format, detailLevel);
- }
-
- @Override protected PreparedResult implement(RelRoot root) {
- if(RelUtils.findOLAPRel(root.rel) && !root.rel.getClass().getName().contains("OLAPToEnumerableConverter")){
- String dumpPlan = RelOptUtil.dumpPlan("", root.rel, false, SqlExplainLevel.DIGEST_ATTRIBUTES);
- throw new IllegalArgumentException("Error planer:" + dumpPlan);
- }
- RelDataType resultType = root.rel.getRowType();
- boolean isDml = root.kind.belongsTo(SqlKind.DML);
- final Bindable bindable;
- if (resultConvention == BindableConvention.INSTANCE) {
- bindable = Interpreters.bindable(root.rel);
- } else {
- EnumerableRel enumerable = (EnumerableRel) root.rel;
- if (!root.isRefTrivial()) {
- final List<RexNode> projects = new ArrayList<>();
- final RexBuilder rexBuilder = enumerable.getCluster().getRexBuilder();
- for (int field : Pair.left(root.fields)) {
- projects.add(rexBuilder.makeInputRef(enumerable, field));
- }
- RexProgram program = RexProgram.create(enumerable.getRowType(),
- projects, null, root.validatedRowType, rexBuilder);
- enumerable = EnumerableCalc.create(enumerable, program);
- }
-
- try {
- CatalogReader.THREAD_LOCAL.set(catalogReader);
- bindable = EnumerableInterpretable.toBindable(internalParameters,
- context.spark(), enumerable, prefer);
- } finally {
- CatalogReader.THREAD_LOCAL.remove();
- }
- }
-
- if (timingTracer != null) {
- timingTracer.traceTime("end codegen");
- }
-
- if (timingTracer != null) {
- timingTracer.traceTime("end compilation");
- }
-
- return new PreparedResultImpl(
- resultType,
- parameterRowType,
- fieldOrigins,
- root.collation.getFieldCollations().isEmpty()
- ? ImmutableList.<RelCollation>of()
- : ImmutableList.of(root.collation),
- root.rel,
- mapTableModOp(isDml, root.kind),
- isDml) {
- public String getCode() {
- throw new UnsupportedOperationException();
- }
-
- public Bindable getBindable(Meta.CursorFactory cursorFactory) {
- return bindable;
- }
-
- public Type getElementType() {
- return ((Typed) bindable).getElementType();
- }
- };
- }
-
- @Override protected List<Materialization> getMaterializations() {
- final List<Materialization> materializations =
- context.config().materializationsEnabled()
- ? MaterializationService.instance().query(schema)
- : ImmutableList.<Prepare.Materialization>of();
- for (Prepare.Materialization materialization : materializations) {
- prepare.populateMaterializations(context, planner, materialization);
- }
- return materializations;
- }
-
- @Override protected List<LatticeEntry> getLattices() {
- return Schemas.getLatticeEntries(schema);
- }
- }
-
- /** An {@code EXPLAIN} statement, prepared and ready to execute. */
- private static class CalcitePreparedExplain extends Prepare.PreparedExplain {
- public CalcitePreparedExplain(
- RelDataType resultType,
- RelDataType parameterRowType,
- RelRoot root,
- SqlExplainFormat format,
- SqlExplainLevel detailLevel) {
- super(resultType, parameterRowType, root, format, detailLevel);
- }
-
- public Bindable getBindable(final Meta.CursorFactory cursorFactory) {
- final String explanation = getCode();
- return new Bindable() {
- public Enumerable bind(DataContext dataContext) {
- switch (cursorFactory.style) {
- case ARRAY:
- return Linq4j.singletonEnumerable(new String[] {explanation});
- case OBJECT:
- default:
- return Linq4j.singletonEnumerable(explanation);
- }
- }
- };
- }
- }
-
- /** Translator from Java AST to {@link RexNode}. */
- interface ScalarTranslator {
- RexNode toRex(BlockStatement statement);
- List<RexNode> toRexList(BlockStatement statement);
- RexNode toRex(Expression expression);
- ScalarTranslator bind(List<ParameterExpression> parameterList,
- List<RexNode> values);
- }
-
- /** Basic translator. */
- static class EmptyScalarTranslator implements ScalarTranslator {
- private final RexBuilder rexBuilder;
-
- public EmptyScalarTranslator(RexBuilder rexBuilder) {
- this.rexBuilder = rexBuilder;
- }
-
- public static ScalarTranslator empty(RexBuilder builder) {
- return new EmptyScalarTranslator(builder);
- }
-
- public List<RexNode> toRexList(BlockStatement statement) {
- final List<Expression> simpleList = simpleList(statement);
- final List<RexNode> list = new ArrayList<>();
- for (Expression expression1 : simpleList) {
- list.add(toRex(expression1));
- }
- return list;
- }
-
- public RexNode toRex(BlockStatement statement) {
- return toRex(Blocks.simple(statement));
- }
-
- private static List<Expression> simpleList(BlockStatement statement) {
- Expression simple = Blocks.simple(statement);
- if (simple instanceof NewExpression) {
- NewExpression newExpression = (NewExpression) simple;
- return newExpression.arguments;
- } else {
- return Collections.singletonList(simple);
- }
- }
-
- public RexNode toRex(Expression expression) {
- switch (expression.getNodeType()) {
- case MemberAccess:
- // Case-sensitive name match because name was previously resolved.
- return rexBuilder.makeFieldAccess(
- toRex(
- ((MemberExpression) expression).expression),
- ((MemberExpression) expression).field.getName(),
- true);
- case GreaterThan:
- return binary(expression, SqlStdOperatorTable.GREATER_THAN);
- case LessThan:
- return binary(expression, SqlStdOperatorTable.LESS_THAN);
- case Parameter:
- return parameter((ParameterExpression) expression);
- case Call:
- MethodCallExpression call = (MethodCallExpression) expression;
- SqlOperator operator =
- RexToLixTranslator.JAVA_TO_SQL_METHOD_MAP.get(call.method);
- if (operator != null) {
- return rexBuilder.makeCall(
- type(call),
- operator,
- toRex(
- Expressions.<Expression>list()
- .appendIfNotNull(call.targetExpression)
- .appendAll(call.expressions)));
- }
- throw new RuntimeException(
- "Could translate call to method " + call.method);
- case Constant:
- final ConstantExpression constant =
- (ConstantExpression) expression;
- Object value = constant.value;
- if (value instanceof Number) {
- Number number = (Number) value;
- if (value instanceof Double || value instanceof Float) {
- return rexBuilder.makeApproxLiteral(
- BigDecimal.valueOf(number.doubleValue()));
- } else if (value instanceof BigDecimal) {
- return rexBuilder.makeExactLiteral((BigDecimal) value);
- } else {
- return rexBuilder.makeExactLiteral(
- BigDecimal.valueOf(number.longValue()));
- }
- } else if (value instanceof Boolean) {
- return rexBuilder.makeLiteral((Boolean) value);
- } else {
- return rexBuilder.makeLiteral(constant.toString());
- }
- default:
- throw new UnsupportedOperationException(
- "unknown expression type " + expression.getNodeType() + " "
- + expression);
- }
- }
-
- private RexNode binary(Expression expression, SqlBinaryOperator op) {
- BinaryExpression call = (BinaryExpression) expression;
- return rexBuilder.makeCall(type(call), op,
- toRex(ImmutableList.of(call.expression0, call.expression1)));
- }
-
- private List<RexNode> toRex(List<Expression> expressions) {
- final List<RexNode> list = new ArrayList<>();
- for (Expression expression : expressions) {
- list.add(toRex(expression));
- }
- return list;
- }
-
- protected RelDataType type(Expression expression) {
- final Type type = expression.getType();
- return ((JavaTypeFactory) rexBuilder.getTypeFactory()).createType(type);
- }
-
- public ScalarTranslator bind(
- List<ParameterExpression> parameterList, List<RexNode> values) {
- return new LambdaScalarTranslator(
- rexBuilder, parameterList, values);
- }
-
- public RexNode parameter(ParameterExpression param) {
- throw new RuntimeException("unknown parameter " + param);
- }
- }
-
- /** Translator that looks for parameters. */
- private static class LambdaScalarTranslator extends EmptyScalarTranslator {
- private final List<ParameterExpression> parameterList;
- private final List<RexNode> values;
-
- public LambdaScalarTranslator(
- RexBuilder rexBuilder,
- List<ParameterExpression> parameterList,
- List<RexNode> values) {
- super(rexBuilder);
- this.parameterList = parameterList;
- this.values = values;
- }
-
- public RexNode parameter(ParameterExpression param) {
- int i = parameterList.indexOf(param);
- if (i >= 0) {
- return values.get(i);
- }
- throw new RuntimeException("unknown parameter " + param);
- }
- }
-}
-
-// End CalcitePrepareImpl.java
diff --git a/atopcalcite/src/main/java/org/apache/calcite/prepare/OnlyPrepareEarlyAbortException.java b/atopcalcite/src/main/java/org/apache/calcite/prepare/OnlyPrepareEarlyAbortException.java
deleted file mode 100644
index 8493484..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/prepare/OnlyPrepareEarlyAbortException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-package org.apache.calcite.prepare;
-
-import org.apache.calcite.jdbc.CalcitePrepare;
-
-public class OnlyPrepareEarlyAbortException extends RuntimeException {
-
- private CalcitePrepare.Context context;
- private org.apache.calcite.jdbc.CalcitePrepare.ParseResult preparedResult;
-
- public OnlyPrepareEarlyAbortException(CalcitePrepare.Context context,
- org.apache.calcite.jdbc.CalcitePrepare.ParseResult preparedResult) {
- this.context = context;
- this.preparedResult = preparedResult;
- }
-
- public CalcitePrepare.Context getContext() {
- return context;
- }
-
- public CalcitePrepare.ParseResult getPreparedResult() {
- return preparedResult;
- }
-}
diff --git a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/atopcalcite/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
deleted file mode 100644
index f758b40..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.rel.rules;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptRuleOperand;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.EquiJoin;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.tools.RelBuilderFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-/**
- * Turn it off.
- * Though try to turn it off in OLAPTableScan, sometimes it still triggerd.
- */
-
-/**
- * Planner rule that pushes filters above and
- * within a join node into the join node and/or its children nodes.
- */
-public abstract class FilterJoinRule extends RelOptRule {
- /** Predicate that always returns true. With this predicate, every filter
- * will be pushed into the ON clause. */
- public static final Predicate TRUE_PREDICATE = new Predicate() {
- public boolean apply(Join join, JoinRelType joinType, RexNode exp) {
- return true;
- }
- };
-
- /** Rule that pushes predicates from a Filter into the Join below them. */
- public static final FilterJoinRule FILTER_ON_JOIN = new FilterIntoJoinRule(true, RelFactories.LOGICAL_BUILDER,
- TRUE_PREDICATE);
-
- /** Dumber version of {@link #FILTER_ON_JOIN}. Not intended for production
- * use, but keeps some tests working for which {@code FILTER_ON_JOIN} is too
- * smart. */
- public static final FilterJoinRule DUMB_FILTER_ON_JOIN = new FilterIntoJoinRule(false, RelFactories.LOGICAL_BUILDER,
- TRUE_PREDICATE);
-
- /** Rule that pushes predicates in a Join into the inputs to the join. */
- public static final FilterJoinRule JOIN = new JoinConditionPushRule(RelFactories.LOGICAL_BUILDER, TRUE_PREDICATE);
-
- /** Whether to try to strengthen join-type. */
- private final boolean smart;
-
- /** Predicate that returns whether a filter is valid in the ON clause of a
- * join for this particular kind of join. If not, Calcite will push it back to
- * above the join. */
- private final Predicate predicate;
-
- //~ Constructors -----------------------------------------------------------
-
- /**
- * Creates a FilterProjectTransposeRule with an explicit root operand and
- * factories.
- */
- protected FilterJoinRule(RelOptRuleOperand operand, String id, boolean smart, RelBuilderFactory relBuilderFactory,
- Predicate predicate) {
- super(operand, relBuilderFactory, "FilterJoinRule:" + id);
- this.smart = smart;
- this.predicate = Preconditions.checkNotNull(predicate);
- }
-
- /**
- * Creates a FilterJoinRule with an explicit root operand and
- * factories.
- */
- @Deprecated // to be removed before 2.0
- protected FilterJoinRule(RelOptRuleOperand operand, String id, boolean smart,
- RelFactories.FilterFactory filterFactory, RelFactories.ProjectFactory projectFactory) {
- this(operand, id, smart, RelBuilder.proto(filterFactory, projectFactory), TRUE_PREDICATE);
- }
-
- /**
- * Creates a FilterProjectTransposeRule with an explicit root operand and
- * factories.
- */
- @Deprecated // to be removed before 2.0
- protected FilterJoinRule(RelOptRuleOperand operand, String id, boolean smart,
- RelFactories.FilterFactory filterFactory, RelFactories.ProjectFactory projectFactory, Predicate predicate) {
- this(operand, id, smart, RelBuilder.proto(filterFactory, projectFactory), predicate);
- }
-
- //~ Methods ----------------------------------------------------------------
-
- protected void perform(RelOptRuleCall call, Filter filter, Join join) {
- final List<RexNode> joinFilters = RelOptUtil.conjunctions(join.getCondition());
- final List<RexNode> origJoinFilters = ImmutableList.copyOf(joinFilters);
-
- // If there is only the joinRel,
- // make sure it does not match a cartesian product joinRel
- // (with "true" condition), otherwise this rule will be applied
- // again on the new cartesian product joinRel.
- if (filter == null && joinFilters.isEmpty()) {
- return;
- }
-
- final List<RexNode> aboveFilters = filter != null ? RelOptUtil.conjunctions(filter.getCondition())
- : Lists.<RexNode> newArrayList();
- final ImmutableList<RexNode> origAboveFilters = ImmutableList.copyOf(aboveFilters);
-
- // Simplify Outer Joins
- JoinRelType joinType = join.getJoinType();
- if (smart && !origAboveFilters.isEmpty() && join.getJoinType() != JoinRelType.INNER) {
- joinType = RelOptUtil.simplifyJoin(join, origAboveFilters, joinType);
- }
-
- final List<RexNode> leftFilters = new ArrayList<>();
- final List<RexNode> rightFilters = new ArrayList<>();
-
- // TODO - add logic to derive additional filters. E.g., from
- // (t1.a = 1 AND t2.a = 2) OR (t1.b = 3 AND t2.b = 4), you can
- // derive table filters:
- // (t1.a = 1 OR t1.b = 3)
- // (t2.a = 2 OR t2.b = 4)
-
- // Try to push down above filters. These are typically where clause
- // filters. They can be pushed down if they are not on the NULL
- // generating side.
- boolean filterPushed = false;
- if (RelOptUtil.classifyFilters(join, aboveFilters, joinType, !(join instanceof EquiJoin),
- !joinType.generatesNullsOnLeft(), !joinType.generatesNullsOnRight(), joinFilters, leftFilters,
- rightFilters)) {
- filterPushed = true;
- }
-
- // Move join filters up if needed
- validateJoinFilters(aboveFilters, joinFilters, join, joinType);
-
- // If no filter got pushed after validate, reset filterPushed flag
- if (leftFilters.isEmpty() && rightFilters.isEmpty() && joinFilters.size() == origJoinFilters.size()) {
- if (Sets.newHashSet(joinFilters).equals(Sets.newHashSet(origJoinFilters))) {
- filterPushed = false;
- }
- }
-
- // Try to push down filters in ON clause. A ON clause filter can only be
- // pushed down if it does not affect the non-matching set, i.e. it is
- // not on the side which is preserved.
- if (RelOptUtil.classifyFilters(join, joinFilters, joinType, false, !joinType.generatesNullsOnRight(),
- !joinType.generatesNullsOnLeft(), joinFilters, leftFilters, rightFilters)) {
- filterPushed = true;
- }
-
- // if nothing actually got pushed and there is nothing leftover,
- // then this rule is a no-op
- if ((!filterPushed && joinType == join.getJoinType())
- || (joinFilters.isEmpty() && leftFilters.isEmpty() && rightFilters.isEmpty())) {
- return;
- }
-
- // create Filters on top of the children if any filters were
- // pushed to them
- final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
- final RelBuilder relBuilder = call.builder();
- final RelNode leftRel = relBuilder.push(join.getLeft()).filter(leftFilters).build();
- final RelNode rightRel = relBuilder.push(join.getRight()).filter(rightFilters).build();
-
- // create the new join node referencing the new children and
- // containing its new join filters (if there are any)
- final ImmutableList<RelDataType> fieldTypes = ImmutableList.<RelDataType> builder()
- .addAll(RelOptUtil.getFieldTypeList(leftRel.getRowType()))
- .addAll(RelOptUtil.getFieldTypeList(rightRel.getRowType())).build();
- final RexNode joinFilter = RexUtil.composeConjunction(rexBuilder,
- RexUtil.fixUp(rexBuilder, joinFilters, fieldTypes), false);
-
- // If nothing actually got pushed and there is nothing leftover,
- // then this rule is a no-op
- if (joinFilter.isAlwaysTrue() && leftFilters.isEmpty() && rightFilters.isEmpty()
- && joinType == join.getJoinType()) {
- return;
- }
-
- RelNode newJoinRel = join.copy(join.getTraitSet(), joinFilter, leftRel, rightRel, joinType,
- join.isSemiJoinDone());
- call.getPlanner().onCopy(join, newJoinRel);
- if (!leftFilters.isEmpty()) {
- call.getPlanner().onCopy(filter, leftRel);
- }
- if (!rightFilters.isEmpty()) {
- call.getPlanner().onCopy(filter, rightRel);
- }
-
- relBuilder.push(newJoinRel);
-
- // Create a project on top of the join if some of the columns have become
- // NOT NULL due to the join-type getting stricter.
- relBuilder.convert(join.getRowType(), false);
-
- // create a FilterRel on top of the join if needed
- relBuilder.filter(
- RexUtil.fixUp(rexBuilder, aboveFilters, RelOptUtil.getFieldTypeList(relBuilder.peek().getRowType())));
-
- call.transformTo(relBuilder.build());
- }
-
- /**
- * Validates that target execution framework can satisfy join filters.
- *
- * <p>If the join filter cannot be satisfied (for example, if it is
- * {@code l.c1 > r.c2} and the join only supports equi-join), removes the
- * filter from {@code joinFilters} and adds it to {@code aboveFilters}.
- *
- * <p>The default implementation does nothing; i.e. the join can handle all
- * conditions.
- *
- * @param aboveFilters Filter above Join
- * @param joinFilters Filters in join condition
- * @param join Join
- * @param joinType JoinRelType could be different from type in Join due to
- * outer join simplification.
- */
- protected void validateJoinFilters(List<RexNode> aboveFilters, List<RexNode> joinFilters, Join join,
- JoinRelType joinType) {
- final Iterator<RexNode> filterIter = joinFilters.iterator();
- while (filterIter.hasNext()) {
- RexNode exp = filterIter.next();
- if (!predicate.apply(join, joinType, exp)) {
- aboveFilters.add(exp);
- filterIter.remove();
- }
- }
- }
-
- /** Rule that pushes parts of the join condition to its inputs. */
- public static class JoinConditionPushRule extends FilterJoinRule {
- public JoinConditionPushRule(RelBuilderFactory relBuilderFactory, Predicate predicate) {
- super(RelOptRule.operand(Join.class, RelOptRule.any()), "FilterJoinRule:no-filter", true, relBuilderFactory,
- predicate);
- }
-
- @Deprecated // to be removed before 2.0
- public JoinConditionPushRule(RelFactories.FilterFactory filterFactory,
- RelFactories.ProjectFactory projectFactory, Predicate predicate) {
- this(RelBuilder.proto(filterFactory, projectFactory), predicate);
- }
-
- @Override
- public void onMatch(RelOptRuleCall call) {
- Join join = call.rel(0);
- // HACK POINT
-// perform(call, null, join);
- }
- }
-
- /** Rule that tries to push filter expressions into a join
- * condition and into the inputs of the join. */
- public static class FilterIntoJoinRule extends FilterJoinRule {
- public FilterIntoJoinRule(boolean smart, RelBuilderFactory relBuilderFactory, Predicate predicate) {
- super(operand(Filter.class, operand(Join.class, RelOptRule.any())), "FilterJoinRule:filter", smart,
- relBuilderFactory, predicate);
- }
-
- @Deprecated // to be removed before 2.0
- public FilterIntoJoinRule(boolean smart, RelFactories.FilterFactory filterFactory,
- RelFactories.ProjectFactory projectFactory, Predicate predicate) {
- this(smart, RelBuilder.proto(filterFactory, projectFactory), predicate);
- }
-
- @Override
- public void onMatch(RelOptRuleCall call) {
- Filter filter = call.rel(0);
- Join join = call.rel(1);
- // HACK POINT
-// perform(call, filter, join);
- }
- }
-
- /** Predicate that returns whether a filter is valid in the ON clause of a
- * join for this particular kind of join. If not, Calcite will push it back to
- * above the join. */
- public interface Predicate {
- boolean apply(Join join, JoinRelType joinType, RexNode exp);
- }
-}
-
-// End FilterJoinRule.java
\ No newline at end of file
diff --git a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule.java b/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule.java
deleted file mode 100644
index 35f2ae6..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-package org.apache.calcite.rel.rules;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rel.logical.LogicalJoin;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexPermuteInputsShuttle;
-import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.tools.RelBuilderFactory;
-import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.mapping.Mappings;
-
-import com.google.common.base.Predicate;
-
-/**
- * modified form org.apache.calcite.rel.rules.JoinPushThroughJoinRule.
- * The goal is to move joins with sub-queries after joins with tables,
- * so that pre-defined join with tables can be matched
- */
-public class OLAPJoinPushThroughJoinRule extends RelOptRule {
- /**
- * Instance of the rule that works on logical joins only, and pushes to the
- * right.
- */
- public static final RelOptRule INSTANCE = new OLAPJoinPushThroughJoinRule("OLAPJoinPushThroughJoinRule", LogicalJoin.class, RelFactories.LOGICAL_BUILDER);
-
- public OLAPJoinPushThroughJoinRule(String description, Class<? extends Join> clazz, RelBuilderFactory relBuilderFactory) {
- super(operand(clazz,
-
- operand(clazz, operand(RelNode.class, any()), operand(RelNode.class, null, new Predicate<RelNode>() {
- @Override
- public boolean apply(@Nullable RelNode input) {
- return !(input instanceof TableScan);
- }
- }, any())),
-
- operand(TableScan.class, any())), relBuilderFactory, description);
- }
-
- @Override
- public void onMatch(RelOptRuleCall call) {
- onMatchRight(call);
- }
-
- private void onMatchRight(RelOptRuleCall call) {
- final Join topJoin = call.rel(0);
- final Join bottomJoin = call.rel(1);
- final RelNode relC = call.rel(4);
- final RelNode relA = bottomJoin.getLeft();
- final RelNode relB = bottomJoin.getRight();
- final RelOptCluster cluster = topJoin.getCluster();
- // Preconditions.checkState(relA == call.rel(2));
- // Preconditions.checkState(relB == call.rel(3));
-
- // topJoin
- // / \
- // bottomJoin C
- // / \
- // A B
-
- final int aCount = relA.getRowType().getFieldCount();
- final int bCount = relB.getRowType().getFieldCount();
- final int cCount = relC.getRowType().getFieldCount();
- final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
-
- // becomes
- //
- // newTopJoin
- // / \
- // newBottomJoin B
- // / \
- // A C
-
- // If either join is not inner, we cannot proceed.
- // (Is this too strict?)
- // if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
- // return;
- // }
-
- // Split the condition of topJoin into a conjunction. Each of the
- // parts that does not use columns from B can be pushed down.
- final List<RexNode> intersecting = new ArrayList<>();
- final List<RexNode> nonIntersecting = new ArrayList<>();
- split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);
-
- // If there's nothing to push down, it's not worth proceeding.
- if (nonIntersecting.isEmpty()) {
- return;
- }
-
- // Split the condition of bottomJoin into a conjunction. Each of the
- // parts that use columns from B will need to be pulled up.
- final List<RexNode> bottomIntersecting = new ArrayList<>();
- final List<RexNode> bottomNonIntersecting = new ArrayList<>();
- split(bottomJoin.getCondition(), bBitSet, bottomIntersecting, bottomNonIntersecting);
-
- // target: | A | C |
- // source: | A | B | C |
- // final Mappings.TargetMapping bottomMapping = Mappings
- // .createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount, aCount + bCount,
- // cCount);
-
- final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
- final List<RexNode> newBottomList = new ArrayList<>();
- new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(nonIntersecting, newBottomList);
- new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(bottomNonIntersecting, newBottomList);
- final RexBuilder rexBuilder = cluster.getRexBuilder();
- RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
- final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
-
- // target: | A | C | B |
- // source: | A | B | C |
- final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
- final List<RexNode> newTopList = new ArrayList<>();
- new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(intersecting, newTopList);
- new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(bottomIntersecting, newTopList);
- RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
- @SuppressWarnings("SuspiciousNameCombination")
- final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
-
- assert !Mappings.isIdentity(topMapping);
- final RelBuilder relBuilder = call.builder();
- relBuilder.push(newTopJoin);
- relBuilder.project(relBuilder.fields(topMapping));
- call.transformTo(relBuilder.build());
- }
-
- /**
- * Splits a condition into conjunctions that do or do not intersect with
- * a given bit set.
- */
- static void split(RexNode condition, ImmutableBitSet bitSet, List<RexNode> intersecting, List<RexNode> nonIntersecting) {
- for (RexNode node : RelOptUtil.conjunctions(condition)) {
- ImmutableBitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
- if (bitSet.intersects(inputBitSet)) {
- intersecting.add(node);
- } else {
- nonIntersecting.add(node);
- }
- }
- }
-}
diff --git a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule2.java b/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule2.java
deleted file mode 100644
index a769cbd..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/rel/rules/OLAPJoinPushThroughJoinRule2.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-package org.apache.calcite.rel.rules;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.rel.core.TableScan;
-import org.apache.calcite.rel.logical.LogicalJoin;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexPermuteInputsShuttle;
-import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.tools.RelBuilderFactory;
-import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.Permutation;
-import org.apache.calcite.util.mapping.AbstractTargetMapping;
-import org.apache.calcite.util.mapping.Mapping;
-import org.apache.calcite.util.mapping.Mappings;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-
-/**
- * modified form org.apache.calcite.rel.rules.JoinPushThroughJoinRule.
- * The goal is to move joins with sub-queries after joins with tables,
- * so that pre-defined join with tables can be matched
- *
- * differ from OLAPJoinPushThroughJoinRule in the pattern to match. OLAPJoinPushThroughJoinRule
- * will generate a result pattern which cannot recursively match OLAPJoinPushThroughJoinRule's pattern.
- * So OLAPJoinPushThroughJoinRule2 is introduced to allow recursive matching
- */
-public class OLAPJoinPushThroughJoinRule2 extends RelOptRule {
- /**
- * Instance of the rule that works on logical joins only, and pushes to the
- * right.
- */
- public static final RelOptRule INSTANCE = new OLAPJoinPushThroughJoinRule2("OLAPJoinPushThroughJoinRule2", LogicalJoin.class, RelFactories.LOGICAL_BUILDER);
-
- public OLAPJoinPushThroughJoinRule2(String description, Class<? extends Join> clazz, RelBuilderFactory relBuilderFactory) {
- super(operand(clazz,
-
- operand(Project.class, //project is added on top by OLAPJoinPushThroughJoinRule
- null, new Predicate<Project>() {
- @Override
- public boolean apply(@Nullable Project input) {
- return input.getPermutation() != null;
- }
- }, operand(clazz, //
- operand(RelNode.class, any()), operand(RelNode.class, null, new Predicate<RelNode>() {
- @Override
- public boolean apply(@Nullable RelNode input) {
- return !(input instanceof TableScan);
- }
- }, any()))),
-
- operand(TableScan.class, any())), relBuilderFactory, description);
- }
-
- @Override
- public void onMatch(RelOptRuleCall call) {
- onMatchRight(call);
- }
-
- private void onMatchRight(RelOptRuleCall call) {
- final Join topJoin = call.rel(0);
- final Project projectOnBottomJoin = call.rel(1);
- final Join bottomJoin = call.rel(2);
- final RelNode relC = call.rel(5);
- final RelNode relA = bottomJoin.getLeft();
- final RelNode relB = bottomJoin.getRight();
- final RelOptCluster cluster = topJoin.getCluster();
- final Permutation projectPermu = projectOnBottomJoin.getPermutation();
- final Permutation inverseProjectPermu = projectPermu.inverse();
- // Preconditions.checkState(relA == call.rel(3));
- // Preconditions.checkState(relB == call.rel(4));
- Preconditions.checkNotNull(projectPermu);
-
- // topJoin
- // / \
- // project C
- // /
- // bottomJoin
- // / \
- // A B
-
- final int aCount = relA.getRowType().getFieldCount();
- final int bCount = relB.getRowType().getFieldCount();
- final int cCount = relC.getRowType().getFieldCount();
- final ImmutableBitSet bBitSetBelowProject = ImmutableBitSet.range(aCount, aCount + bCount);
- final ImmutableBitSet bBitSetAboveProject = Mappings.apply(inverseProjectPermu, bBitSetBelowProject);
-
- final Mapping extendedProjectPerm = createAbstractTargetMapping(Mappings.append(projectPermu, Mappings.createIdentity(cCount)));
-
- // becomes
- //
- // project
- // /
- // newTopJoin
- // / \
- // newBottomJoin B
- // / \
- // A C
-
- // If either join is not inner, we cannot proceed.
- // (Is this too strict?)
- // if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
- // return;
- // }
-
- // Split the condition of topJoin into a conjunction. Each of the
- // parts that does not use columns from B can be pushed down.
- final List<RexNode> intersecting = new ArrayList<>();
- final List<RexNode> nonIntersecting = new ArrayList<>();
- split(topJoin.getCondition(), bBitSetAboveProject, intersecting, nonIntersecting);
-
- // If there's nothing to push down, it's not worth proceeding.
- if (nonIntersecting.isEmpty()) {
- return;
- }
-
- // Split the condition of bottomJoin into a conjunction. Each of the
- // parts that use columns from B will need to be pulled up.
- final List<RexNode> bottomIntersecting = new ArrayList<>();
- final List<RexNode> bottomNonIntersecting = new ArrayList<>();
- split(bottomJoin.getCondition(), bBitSetBelowProject, bottomIntersecting, bottomNonIntersecting);
- Preconditions.checkState(bottomNonIntersecting.isEmpty());
-
- // target: | A | C |
- // source: | A | B | C |
- final Mappings.TargetMapping tempMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
- final Mappings.TargetMapping thruProjectMapping = Mappings.multiply(extendedProjectPerm, createAbstractTargetMapping(tempMapping));
- final List<RexNode> newBottomList = new ArrayList<>();
- new RexPermuteInputsShuttle(thruProjectMapping, relA, relC).visitList(nonIntersecting, newBottomList);
- final RexBuilder rexBuilder = cluster.getRexBuilder();
- RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
- final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
-
- // target: | A | C | B |
- // source: | A | B | C |
- final Mappings.TargetMapping nonThruProjectMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
- final List<RexNode> newTopList = new ArrayList<>();
- new RexPermuteInputsShuttle(thruProjectMapping, newBottomJoin, relB).visitList(intersecting, newTopList);
- new RexPermuteInputsShuttle(nonThruProjectMapping, newBottomJoin, relB).visitList(bottomIntersecting, newTopList);
- RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
- @SuppressWarnings("SuspiciousNameCombination")
- final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
-
- assert !Mappings.isIdentity(thruProjectMapping);
- final RelBuilder relBuilder = call.builder();
- relBuilder.push(newTopJoin);
- relBuilder.project(relBuilder.fields(thruProjectMapping));
- call.transformTo(relBuilder.build());
- }
-
- private AbstractTargetMapping createAbstractTargetMapping(final Mappings.TargetMapping targetMapping) {
- return new AbstractTargetMapping(targetMapping.getSourceCount(), targetMapping.getTargetCount()) {
- @Override
- public int getTargetOpt(int source) {
- return targetMapping.getTargetOpt(source);
- }
- };
- }
-
- /**
- * Splits a condition into conjunctions that do or do not intersect with
- * a given bit set.
- */
- static void split(RexNode condition, ImmutableBitSet bitSet, List<RexNode> intersecting, List<RexNode> nonIntersecting) {
- for (RexNode node : RelOptUtil.conjunctions(condition)) {
- ImmutableBitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
- if (bitSet.intersects(inputBitSet)) {
- intersecting.add(node);
- } else {
- nonIntersecting.add(node);
- }
- }
- }
-}
diff --git a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
deleted file mode 100644
index 38bd223..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ /dev/null
@@ -1,2238 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.runtime;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TimeZone;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.regex.Pattern;
-
-import org.apache.calcite.DataContext;
-import org.apache.calcite.avatica.util.ByteString;
-import org.apache.calcite.avatica.util.DateTimeUtils;
-import org.apache.calcite.avatica.util.Spaces;
-import org.apache.calcite.avatica.util.TimeUnitRange;
-import org.apache.calcite.linq4j.AbstractEnumerable;
-import org.apache.calcite.linq4j.CartesianProductEnumerator;
-import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.linq4j.Enumerator;
-import org.apache.calcite.linq4j.Linq4j;
-import org.apache.calcite.linq4j.function.Deterministic;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.NonDeterministic;
-import org.apache.calcite.linq4j.tree.Primitive;
-import org.apache.calcite.runtime.FlatLists.ComparableList;
-import org.apache.calcite.util.Bug;
-import org.apache.calcite.util.NumberUtil;
-
-/*
- * OVERRIDE POINT:
- * - more power() overloads
- * - refined org.apache.calcite.runtime.SqlFunctions#addMonths(int, int)
- * - corner case subString()
- * - corner case trim_()
- * - upper()
- * - lower()
- * - charLength()
- * - addMonths()
- */
-
-/**
- * Helper methods to implement SQL functions in generated code.
- *
- * <p>Not present: and, or, not (builtin operators are better, because they
- * use lazy evaluation. Implementations do not check for null values; the
- * calling code must do that.</p>
- *
- * <p>Many of the functions do not check for null values. This is intentional.
- * If null arguments are possible, the code-generation framework checks for
- * nulls before calling the functions.</p>
- */
-
-@SuppressWarnings("UnnecessaryUnboxing")
-@Deterministic
-public class SqlFunctions {
- private static final DecimalFormat DOUBLE_FORMAT = NumberUtil.decimalFormat("0.0E0");
-
- private static final TimeZone LOCAL_TZ = TimeZone.getDefault();
-
- private static final Function1<List<Object>, Enumerable<Object>> LIST_AS_ENUMERABLE = new Function1<List<Object>, Enumerable<Object>>() {
- public Enumerable<Object> apply(List<Object> list) {
- return Linq4j.asEnumerable(list);
- }
- };
-
- private static final Function1<Object[], Enumerable<Object[]>> ARRAY_CARTESIAN_PRODUCT = new Function1<Object[], Enumerable<Object[]>>() {
- public Enumerable<Object[]> apply(Object[] lists) {
- final List<Enumerator<Object>> enumerators = new ArrayList<>();
- for (Object list : lists) {
- enumerators.add(Linq4j.enumerator((List) list));
- }
- final Enumerator<List<Object>> product = Linq4j.product(enumerators);
- return new AbstractEnumerable<Object[]>() {
- public Enumerator<Object[]> enumerator() {
- return Linq4j.transform(product, new Function1<List<Object>, Object[]>() {
- public Object[] apply(List<Object> list) {
- return list.toArray();
- }
- });
- }
- };
- }
- };
-
- /** Holds, for each thread, a map from sequence name to sequence current
- * value.
- *
- * <p>This is a straw man of an implementation whose main goal is to prove
- * that sequences can be parsed, validated and planned. A real application
- * will want persistent values for sequences, shared among threads. */
- private static final ThreadLocal<Map<String, AtomicLong>> THREAD_SEQUENCES = new ThreadLocal<Map<String, AtomicLong>>() {
- @Override
- protected Map<String, AtomicLong> initialValue() {
- return new HashMap<String, AtomicLong>();
- }
- };
-
- private SqlFunctions() {
- }
-
- /** SQL SUBSTRING(string FROM ... FOR ...) function. */
- // override
- public static String substring(String s, int from, int for_) {
- if (s == null) {
- return null;
- }
- return s.substring(from - 1, Math.min(from - 1 + for_, s.length()));
- }
-
- public static String substring(String s, long from, long for_) {
- if (from < Integer.MIN_VALUE || from > Integer.MAX_VALUE || for_ < Integer.MIN_VALUE
- || for_ > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Cannot be cast to int due to risk of overflow.");
- }
- return substring(s, (int) from, (int) for_);
- }
-
- /** SQL SUBSTRING(string FROM ...) function. */
- public static String substring(String s, int from) {
- return s.substring(from - 1);
- }
-
- public static String substring(String s, long from) {
- if (from < Integer.MIN_VALUE || from > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Cannot be cast to int due to risk of overflow.");
- }
- return substring(s, (int) from);
- }
-
- /** SQL SUBSTRING(binary FROM ... FOR ...) function. */
- public static ByteString substring(ByteString b, int from, int for_) {
- return b.substring(from - 1, Math.min(from - 1 + for_, b.length()));
- }
-
- public static ByteString substring(ByteString b, long from, long for_) {
- if (from < Integer.MIN_VALUE || from > Integer.MAX_VALUE || for_ < Integer.MIN_VALUE
- || for_ > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Cannot be cast to int due to risk of overflow.");
- }
- return substring(b, (int) from, (int) for_);
- }
-
- /** SQL SUBSTRING(binary FROM ...) function. */
- public static ByteString substring(ByteString b, int from) {
- return b.substring(from - 1);
- }
-
- public static ByteString substring(ByteString b, long from) {
- if (from < Integer.MIN_VALUE || from > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Cannot be cast to int due to risk of overflow.");
- }
- return substring(b, (int) from);
- }
-
- /** SQL UPPER(string) function. */
- //overrivde
- public static String upper(String s) {
- if (s == null) {
- return "";
- }
- return s.toUpperCase(Locale.ROOT);
- }
-
- /** SQL LOWER(string) function. */
- //override
- public static String lower(String s) {
- if (s == null) {
- return "";
- }
- return s.toLowerCase(Locale.ROOT);
- }
-
- /** SQL INITCAP(string) function. */
- public static String initcap(String s) {
- // Assumes Alpha as [A-Za-z0-9]
- // white space is treated as everything else.
- final int len = s.length();
- boolean start = true;
- final StringBuilder newS = new StringBuilder();
-
- for (int i = 0; i < len; i++) {
- char curCh = s.charAt(i);
- final int c = (int) curCh;
- if (start) { // curCh is whitespace or first character of word.
- if (c > 47 && c < 58) { // 0-9
- start = false;
- } else if (c > 64 && c < 91) { // A-Z
- start = false;
- } else if (c > 96 && c < 123) { // a-z
- start = false;
- curCh = (char) (c - 32); // Uppercase this character
- }
- // else {} whitespace
- } else { // Inside of a word or white space after end of word.
- if (c > 47 && c < 58) { // 0-9
- // noop
- } else if (c > 64 && c < 91) { // A-Z
- curCh = (char) (c + 32); // Lowercase this character
- } else if (c > 96 && c < 123) { // a-z
- // noop
- } else { // whitespace
- start = true;
- }
- }
- newS.append(curCh);
- } // for each character in s
- return newS.toString();
- }
-
- /** SQL CHARACTER_LENGTH(string) function. */
- public static int charLength(String s) {
- if (s == null) {
- return 0;
- }
- return s.length();
- }
-
- /** SQL {@code string || string} operator. */
- public static String concat(String s0, String s1) {
- return s0 + s1;
- }
-
- /** SQL {@code binary || binary} operator. */
- public static ByteString concat(ByteString s0, ByteString s1) {
- return s0.concat(s1);
- }
-
- /** SQL {@code RTRIM} function applied to string. */
- public static String rtrim(String s) {
- return trim_(s, false, true, ' ');
- }
-
- /** SQL {@code LTRIM} function. */
- public static String ltrim(String s) {
- return trim_(s, true, false, ' ');
- }
-
- /** SQL {@code TRIM(... seek FROM s)} function. */
- public static String trim(boolean leading, boolean trailing, String seek, String s) {
- return trim_(s, leading, trailing, seek.charAt(0));
- }
-
- /** SQL {@code TRIM} function. */
- private static String trim_(String s, boolean left, boolean right, char c) {
- if (s == null) {
- return null;
- }
- int j = s.length();
- if (right) {
- for (;;) {
- if (j == 0) {
- return "";
- }
- if (s.charAt(j - 1) != c) {
- break;
- }
- --j;
- }
- }
- int i = 0;
- if (left) {
- for (;;) {
- if (i == j) {
- return "";
- }
- if (s.charAt(i) != c) {
- break;
- }
- ++i;
- }
- }
- return s.substring(i, j);
- }
-
- /** SQL {@code TRIM} function applied to binary string. */
- public static ByteString trim(ByteString s) {
- return trim_(s, true, true);
- }
-
- /** Helper for CAST. */
- public static ByteString rtrim(ByteString s) {
- return trim_(s, false, true);
- }
-
- /** SQL {@code TRIM} function applied to binary string. */
- private static ByteString trim_(ByteString s, boolean left, boolean right) {
- int j = s.length();
- if (right) {
- for (;;) {
- if (j == 0) {
- return ByteString.EMPTY;
- }
- if (s.byteAt(j - 1) != 0) {
- break;
- }
- --j;
- }
- }
- int i = 0;
- if (left) {
- for (;;) {
- if (i == j) {
- return ByteString.EMPTY;
- }
- if (s.byteAt(i) != 0) {
- break;
- }
- ++i;
- }
- }
- return s.substring(i, j);
- }
-
- /** SQL {@code OVERLAY} function. */
- public static String overlay(String s, String r, int start) {
- if (s == null || r == null) {
- return null;
- }
- return s.substring(0, start - 1) + r + s.substring(start - 1 + r.length());
- }
-
- /** SQL {@code OVERLAY} function. */
- public static String overlay(String s, String r, int start, int length) {
- if (s == null || r == null) {
- return null;
- }
- return s.substring(0, start - 1) + r + s.substring(start - 1 + length);
- }
-
- /** SQL {@code OVERLAY} function applied to binary strings. */
- public static ByteString overlay(ByteString s, ByteString r, int start) {
- if (s == null || r == null) {
- return null;
- }
- return s.substring(0, start - 1).concat(r).concat(s.substring(start - 1 + r.length()));
- }
-
- /** SQL {@code OVERLAY} function applied to binary strings. */
- public static ByteString overlay(ByteString s, ByteString r, int start, int length) {
- if (s == null || r == null) {
- return null;
- }
- return s.substring(0, start - 1).concat(r).concat(s.substring(start - 1 + length));
- }
-
- /** SQL {@code LIKE} function. */
- public static boolean like(String s, String pattern) {
- final String regex = Like.sqlToRegexLike(pattern, null);
- return Pattern.matches(regex, s);
- }
-
- /** SQL {@code LIKE} function with escape. */
- public static boolean like(String s, String pattern, String escape) {
- final String regex = Like.sqlToRegexLike(pattern, escape);
- return Pattern.matches(regex, s);
- }
-
- /** SQL {@code SIMILAR} function. */
- public static boolean similar(String s, String pattern) {
- final String regex = Like.sqlToRegexSimilar(pattern, null);
- return Pattern.matches(regex, s);
- }
-
- /** SQL {@code SIMILAR} function with escape. */
- public static boolean similar(String s, String pattern, String escape) {
- final String regex = Like.sqlToRegexSimilar(pattern, escape);
- return Pattern.matches(regex, s);
- }
-
- // =
-
- /** SQL <code>=</code> operator applied to BigDecimal values (neither may be
- * null). */
- public static boolean eq(BigDecimal b0, BigDecimal b1) {
- return b0.stripTrailingZeros().equals(b1.stripTrailingZeros());
- }
-
- /** SQL <code>=</code> operator applied to Object values (including String;
- * neither side may be null). */
- public static boolean eq(Object b0, Object b1) {
- return b0.equals(b1);
- }
-
- /** SQL <code>=</code> operator applied to Object values (at least one operand
- * has ANY type; neither may be null). */
- public static boolean eqAny(Object b0, Object b1) {
- if (b0.getClass().equals(b1.getClass())) {
- // The result of SqlFunctions.eq(BigDecimal, BigDecimal) makes more sense
- // than BigDecimal.equals(BigDecimal). So if both of types are BigDecimal,
- // we just use SqlFunctions.eq(BigDecimal, BigDecimal).
- if (BigDecimal.class.isInstance(b0)) {
- return eq((BigDecimal) b0, (BigDecimal) b1);
- } else {
- return b0.equals(b1);
- }
- } else if (allAssignable(Number.class, b0, b1)) {
- return eq(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
- // We shouldn't rely on implementation even though overridden equals can
- // handle other types which may create worse result: for example,
- // a.equals(b) != b.equals(a)
- return false;
- }
-
- /** Returns whether two objects can both be assigned to a given class. */
- private static boolean allAssignable(Class clazz, Object o0, Object o1) {
- return clazz.isInstance(o0) && clazz.isInstance(o1);
- }
-
- // <>
-
- /** SQL <code><gt;</code> operator applied to BigDecimal values. */
- public static boolean ne(BigDecimal b0, BigDecimal b1) {
- return b0.compareTo(b1) != 0;
- }
-
- /** SQL <code><gt;</code> operator applied to Object values (including
- * String; neither side may be null). */
- public static boolean ne(Object b0, Object b1) {
- return !eq(b0, b1);
- }
-
- /** SQL <code><gt;</code> operator applied to Object values (at least one
- * operand has ANY type, including String; neither may be null). */
- public static boolean neAny(Object b0, Object b1) {
- return !eqAny(b0, b1);
- }
-
- // <
-
- /** SQL <code><</code> operator applied to boolean values. */
- public static boolean lt(boolean b0, boolean b1) {
- return compare(b0, b1) < 0;
- }
-
- /** SQL <code><</code> operator applied to String values. */
- public static boolean lt(String b0, String b1) {
- return b0.compareTo(b1) < 0;
- }
-
- /** SQL <code><</code> operator applied to ByteString values. */
- public static boolean lt(ByteString b0, ByteString b1) {
- return b0.compareTo(b1) < 0;
- }
-
- /** SQL <code><</code> operator applied to BigDecimal values. */
- public static boolean lt(BigDecimal b0, BigDecimal b1) {
- return b0.compareTo(b1) < 0;
- }
-
- /** SQL <code><</code> operator applied to Object values. */
- public static boolean ltAny(Object b0, Object b1) {
- if (b0.getClass().equals(b1.getClass()) && b0 instanceof Comparable) {
- //noinspection unchecked
- return ((Comparable) b0).compareTo(b1) < 0;
- } else if (allAssignable(Number.class, b0, b1)) {
- return lt(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notComparable("<", b0, b1);
- }
-
- // <=
-
- /** SQL <code>≤</code> operator applied to boolean values. */
- public static boolean le(boolean b0, boolean b1) {
- return compare(b0, b1) <= 0;
- }
-
- /** SQL <code>≤</code> operator applied to String values. */
- public static boolean le(String b0, String b1) {
- return b0.compareTo(b1) <= 0;
- }
-
- /** SQL <code>≤</code> operator applied to ByteString values. */
- public static boolean le(ByteString b0, ByteString b1) {
- return b0.compareTo(b1) <= 0;
- }
-
- /** SQL <code>≤</code> operator applied to BigDecimal values. */
- public static boolean le(BigDecimal b0, BigDecimal b1) {
- return b0.compareTo(b1) <= 0;
- }
-
- /** SQL <code>≤</code> operator applied to Object values (at least one
- * operand has ANY type; neither may be null). */
- public static boolean leAny(Object b0, Object b1) {
- if (b0.getClass().equals(b1.getClass()) && b0 instanceof Comparable) {
- //noinspection unchecked
- return ((Comparable) b0).compareTo(b1) <= 0;
- } else if (allAssignable(Number.class, b0, b1)) {
- return le(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notComparable("<=", b0, b1);
- }
-
- // >
-
- /** SQL <code>></code> operator applied to boolean values. */
- public static boolean gt(boolean b0, boolean b1) {
- return compare(b0, b1) > 0;
- }
-
- /** SQL <code>></code> operator applied to String values. */
- public static boolean gt(String b0, String b1) {
- return b0.compareTo(b1) > 0;
- }
-
- /** SQL <code>></code> operator applied to ByteString values. */
- public static boolean gt(ByteString b0, ByteString b1) {
- return b0.compareTo(b1) > 0;
- }
-
- /** SQL <code>></code> operator applied to BigDecimal values. */
- public static boolean gt(BigDecimal b0, BigDecimal b1) {
- return b0.compareTo(b1) > 0;
- }
-
- /** SQL <code>></code> operator applied to Object values (at least one
- * operand has ANY type; neither may be null). */
- public static boolean gtAny(Object b0, Object b1) {
- if (b0.getClass().equals(b1.getClass()) && b0 instanceof Comparable) {
- //noinspection unchecked
- return ((Comparable) b0).compareTo(b1) > 0;
- } else if (allAssignable(Number.class, b0, b1)) {
- return gt(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notComparable(">", b0, b1);
- }
-
- // >=
-
- /** SQL <code>≥</code> operator applied to boolean values. */
- public static boolean ge(boolean b0, boolean b1) {
- return compare(b0, b1) >= 0;
- }
-
- /** SQL <code>≥</code> operator applied to String values. */
- public static boolean ge(String b0, String b1) {
- return b0.compareTo(b1) >= 0;
- }
-
- /** SQL <code>≥</code> operator applied to ByteString values. */
- public static boolean ge(ByteString b0, ByteString b1) {
- return b0.compareTo(b1) >= 0;
- }
-
- /** SQL <code>≥</code> operator applied to BigDecimal values. */
- public static boolean ge(BigDecimal b0, BigDecimal b1) {
- return b0.compareTo(b1) >= 0;
- }
-
- /** SQL <code>≥</code> operator applied to Object values (at least one
- * operand has ANY type; neither may be null). */
- public static boolean geAny(Object b0, Object b1) {
- if (b0.getClass().equals(b1.getClass()) && b0 instanceof Comparable) {
- //noinspection unchecked
- return ((Comparable) b0).compareTo(b1) >= 0;
- } else if (allAssignable(Number.class, b0, b1)) {
- return ge(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notComparable(">=", b0, b1);
- }
-
- // +
-
- /** SQL <code>+</code> operator applied to int values. */
- public static int plus(int b0, int b1) {
- return b0 + b1;
- }
-
- /** SQL <code>+</code> operator applied to int values; left side may be
- * null. */
- public static Integer plus(Integer b0, int b1) {
- return b0 == null ? null : (b0 + b1);
- }
-
- /** SQL <code>+</code> operator applied to int values; right side may be
- * null. */
- public static Integer plus(int b0, Integer b1) {
- return b1 == null ? null : (b0 + b1);
- }
-
- /** SQL <code>+</code> operator applied to nullable int values. */
- public static Integer plus(Integer b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0 + b1);
- }
-
- /** SQL <code>+</code> operator applied to nullable long and int values. */
- public static Long plus(Long b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() + b1.longValue());
- }
-
- /** SQL <code>+</code> operator applied to nullable int and long values. */
- public static Long plus(Integer b0, Long b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() + b1.longValue());
- }
-
- /** SQL <code>+</code> operator applied to BigDecimal values. */
- public static BigDecimal plus(BigDecimal b0, BigDecimal b1) {
- return (b0 == null || b1 == null) ? null : b0.add(b1);
- }
-
- /** SQL <code>+</code> operator applied to String values. Same as string concat operator. */
- public static String plus(String s0, String s1) {
- return s0 + s1;
- }
-
- /** SQL <code>+</code> operator applied to Object values (at least one operand
- * has ANY type; either may be null). */
- public static Object plusAny(Object b0, Object b1) {
- if (b0 == null || b1 == null) {
- return null;
- }
-
- if (allAssignable(Number.class, b0, b1)) {
- return plus(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notArithmetic("+", b0, b1);
- }
-
- // -
-
- /** SQL <code>-</code> operator applied to int values. */
- public static int minus(int b0, int b1) {
- return b0 - b1;
- }
-
- /** SQL <code>-</code> operator applied to int values; left side may be
- * null. */
- public static Integer minus(Integer b0, int b1) {
- return b0 == null ? null : (b0 - b1);
- }
-
- /** SQL <code>-</code> operator applied to int values; right side may be
- * null. */
- public static Integer minus(int b0, Integer b1) {
- return b1 == null ? null : (b0 - b1);
- }
-
- /** SQL <code>-</code> operator applied to nullable int values. */
- public static Integer minus(Integer b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0 - b1);
- }
-
- /** SQL <code>-</code> operator applied to nullable long and int values. */
- public static Long minus(Long b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() - b1.longValue());
- }
-
- /** SQL <code>-</code> operator applied to nullable int and long values. */
- public static Long minus(Integer b0, Long b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() - b1.longValue());
- }
-
- /** SQL <code>-</code> operator applied to BigDecimal values. */
- public static BigDecimal minus(BigDecimal b0, BigDecimal b1) {
- return (b0 == null || b1 == null) ? null : b0.subtract(b1);
- }
-
- /** SQL <code>-</code> operator applied to Object values (at least one operand
- * has ANY type; either may be null). */
- public static Object minusAny(Object b0, Object b1) {
- if (b0 == null || b1 == null) {
- return null;
- }
-
- if (allAssignable(Number.class, b0, b1)) {
- return minus(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notArithmetic("-", b0, b1);
- }
-
- // /
-
- /** SQL <code>/</code> operator applied to int values. */
- public static int divide(int b0, int b1) {
- return b0 / b1;
- }
-
- /** SQL <code>/</code> operator applied to int values; left side may be
- * null. */
- public static Integer divide(Integer b0, int b1) {
- return b0 == null ? null : (b0 / b1);
- }
-
- /** SQL <code>/</code> operator applied to int values; right side may be
- * null. */
- public static Integer divide(int b0, Integer b1) {
- return b1 == null ? null : (b0 / b1);
- }
-
- /** SQL <code>/</code> operator applied to nullable int values. */
- public static Integer divide(Integer b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0 / b1);
- }
-
- /** SQL <code>/</code> operator applied to nullable long and int values. */
- public static Long divide(Long b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() / b1.longValue());
- }
-
- /** SQL <code>/</code> operator applied to nullable int and long values. */
- public static Long divide(Integer b0, Long b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() / b1.longValue());
- }
-
- /** SQL <code>/</code> operator applied to BigDecimal values. */
- public static BigDecimal divide(BigDecimal b0, BigDecimal b1) {
- return (b0 == null || b1 == null) ? null : b0.divide(b1, MathContext.DECIMAL64);
- }
-
- /** SQL <code>/</code> operator applied to Object values (at least one operand
- * has ANY type; either may be null). */
- public static Object divideAny(Object b0, Object b1) {
- if (b0 == null || b1 == null) {
- return null;
- }
-
- if (allAssignable(Number.class, b0, b1)) {
- return divide(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notArithmetic("/", b0, b1);
- }
-
- public static int divide(int b0, BigDecimal b1) {
- return BigDecimal.valueOf(b0).divide(b1, RoundingMode.HALF_DOWN).intValue();
- }
-
- public static long divide(long b0, BigDecimal b1) {
- return BigDecimal.valueOf(b0).divide(b1, RoundingMode.HALF_DOWN).longValue();
- }
-
- // *
-
- /** SQL <code>*</code> operator applied to int values. */
- public static int multiply(int b0, int b1) {
- return b0 * b1;
- }
-
- /** SQL <code>*</code> operator applied to int values; left side may be
- * null. */
- public static Integer multiply(Integer b0, int b1) {
- return b0 == null ? null : (b0 * b1);
- }
-
- /** SQL <code>*</code> operator applied to int values; right side may be
- * null. */
- public static Integer multiply(int b0, Integer b1) {
- return b1 == null ? null : (b0 * b1);
- }
-
- /** SQL <code>*</code> operator applied to nullable int values. */
- public static Integer multiply(Integer b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0 * b1);
- }
-
- /** SQL <code>*</code> operator applied to nullable long and int values. */
- public static Long multiply(Long b0, Integer b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() * b1.longValue());
- }
-
- /** SQL <code>*</code> operator applied to nullable int and long values. */
- public static Long multiply(Integer b0, Long b1) {
- return (b0 == null || b1 == null) ? null : (b0.longValue() * b1.longValue());
- }
-
- /** SQL <code>*</code> operator applied to BigDecimal values. */
- public static BigDecimal multiply(BigDecimal b0, BigDecimal b1) {
- return (b0 == null || b1 == null) ? null : b0.multiply(b1);
- }
-
- /** SQL <code>*</code> operator applied to Object values (at least one operand
- * has ANY type; either may be null). */
- public static Object multiplyAny(Object b0, Object b1) {
- if (b0 == null || b1 == null) {
- return null;
- }
-
- if (allAssignable(Number.class, b0, b1)) {
- return multiply(toBigDecimal((Number) b0), toBigDecimal((Number) b1));
- }
-
- throw notArithmetic("*", b0, b1);
- }
-
- private static IllegalArgumentException notArithmetic(String op, Object b0, Object b1) {
- return new IllegalArgumentException(
- "Invalid types for arithmetic: " + b0.getClass() + " " + op + " " + b1.getClass());
- }
-
- private static IllegalArgumentException notComparable(String op, Object b0, Object b1) {
- return new IllegalArgumentException(
- "Invalid types for comparison: " + b0.getClass() + " " + op + " " + b1.getClass());
- }
-
- // EXP
-
- /** SQL <code>EXP</code> operator applied to double values. */
- public static double exp(double b0) {
- return Math.exp(b0);
- }
-
- public static double exp(BigDecimal b0) {
- return Math.exp(b0.doubleValue());
- }
-
- public static double exp(long b0) {
- return Math.exp(b0);
- }
-
- // POWER
-
- /** SQL <code>POWER</code> operator applied to double values. */
- public static double power(double b0, double b1) {
- return Math.pow(b0, b1);
- }
-
- public static double power(long b0, long b1) {
- return Math.pow(b0, b1);
- }
-
- public static double power(BigDecimal b0, BigDecimal b1) {
- return Math.pow(b0.doubleValue(), b1.doubleValue());
- }
-
- public static double power(long b0, BigDecimal b1) {
- return Math.pow(b0, b1.doubleValue());
- }
-
- // OVERRIDE POINT starts, more power overloads
- public static double power(double n1, long n2) {
- return Math.pow(n1, (double) n2);
- }
-
- public static double power(double n1, BigDecimal n2) {
- return Math.pow(n1, n2.doubleValue());
- }
-
- public static double power(long n1, double n2) {
- return Math.pow((double) n1, n2);
- }
-
- public static double power(BigDecimal n1, double n2) {
- return Math.pow(n1.doubleValue(), n2);
- }
-
- public static double power(BigDecimal n1, long n2) {
- return Math.pow(n1.doubleValue(), (double) n2);
- }
-
- public static double power(double n1, int n2) {
- return Math.pow(n1, (double) n2);
- }
-
- public static double power(long n1, int n2) {
- return Math.pow((double) n1, (double) n2);
- }
-
- public static double power(BigDecimal n1, int n2) {
- return Math.pow(n1.doubleValue(), (double) n2);
- }
-
- public static double power(int n1, double n2) {
- return Math.pow((double) n1, n2);
- }
-
- public static double power(int n1, long n2) {
- return Math.pow((double) n1, (double) n2);
- }
-
- public static double power(int n1, BigDecimal n2) {
- return Math.pow((double) n1, n2.doubleValue());
- }
-
- public static double power(int n1, int n2) {
- return Math.pow(n1, n2);
- }
-
- // OVERRIDE POINT ends, more power overloads
-
- // LN
-
- /** SQL {@code LN(number)} function applied to double values. */
- public static double ln(double d) {
- return Math.log(d);
- }
-
- /** SQL {@code LN(number)} function applied to long values. */
- public static double ln(long b0) {
- return Math.log(b0);
- }
-
- /** SQL {@code LN(number)} function applied to BigDecimal values. */
- public static double ln(BigDecimal d) {
- return Math.log(d.doubleValue());
- }
-
- // LOG10
-
- /** SQL <code>LOG10(numeric)</code> operator applied to double values. */
- public static double log10(double b0) {
- return Math.log10(b0);
- }
-
- /** SQL {@code LOG10(number)} function applied to long values. */
- public static double log10(long b0) {
- return Math.log10(b0);
- }
-
- /** SQL {@code LOG10(number)} function applied to BigDecimal values. */
- public static double log10(BigDecimal d) {
- return Math.log10(d.doubleValue());
- }
-
- // MOD
-
- /** SQL <code>MOD</code> operator applied to byte values. */
- public static byte mod(byte b0, byte b1) {
- return (byte) (b0 % b1);
- }
-
- /** SQL <code>MOD</code> operator applied to short values. */
- public static short mod(short b0, short b1) {
- return (short) (b0 % b1);
- }
-
- /** SQL <code>MOD</code> operator applied to int values. */
- public static int mod(int b0, int b1) {
- return b0 % b1;
- }
-
- /** SQL <code>MOD</code> operator applied to long values. */
- public static long mod(long b0, long b1) {
- return b0 % b1;
- }
-
- // temporary
- public static BigDecimal mod(BigDecimal b0, int b1) {
- return mod(b0, BigDecimal.valueOf(b1));
- }
-
- // temporary
- public static int mod(int b0, BigDecimal b1) {
- return mod(b0, b1.intValue());
- }
-
- public static BigDecimal mod(BigDecimal b0, BigDecimal b1) {
- final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
- return bigDecimals[1];
- }
-
- // FLOOR
-
- public static double floor(double b0) {
- return Math.floor(b0);
- }
-
- public static float floor(float b0) {
- return (float) Math.floor(b0);
- }
-
- public static BigDecimal floor(BigDecimal b0) {
- return b0.setScale(0, RoundingMode.FLOOR);
- }
-
- /** SQL <code>FLOOR</code> operator applied to byte values. */
- public static byte floor(byte b0, byte b1) {
- return (byte) floor((int) b0, (int) b1);
- }
-
- /** SQL <code>FLOOR</code> operator applied to short values. */
- public static short floor(short b0, short b1) {
- return (short) floor((int) b0, (int) b1);
- }
-
- /** SQL <code>FLOOR</code> operator applied to int values. */
- public static int floor(int b0, int b1) {
- int r = b0 % b1;
- if (r < 0) {
- r += b1;
- }
- return b0 - r;
- }
-
- /** SQL <code>FLOOR</code> operator applied to long values. */
- public static long floor(long b0, long b1) {
- long r = b0 % b1;
- if (r < 0) {
- r += b1;
- }
- return b0 - r;
- }
-
- // temporary
- public static BigDecimal floor(BigDecimal b0, int b1) {
- return floor(b0, BigDecimal.valueOf(b1));
- }
-
- // temporary
- public static int floor(int b0, BigDecimal b1) {
- return floor(b0, b1.intValue());
- }
-
- public static BigDecimal floor(BigDecimal b0, BigDecimal b1) {
- final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
- BigDecimal r = bigDecimals[1];
- if (r.signum() < 0) {
- r = r.add(b1);
- }
- return b0.subtract(r);
- }
-
- // CEIL
-
- public static double ceil(double b0) {
- return Math.ceil(b0);
- }
-
- public static float ceil(float b0) {
- return (float) Math.ceil(b0);
- }
-
- public static BigDecimal ceil(BigDecimal b0) {
- return b0.setScale(0, RoundingMode.CEILING);
- }
-
- /** SQL <code>CEIL</code> operator applied to byte values. */
- public static byte ceil(byte b0, byte b1) {
- return floor((byte) (b0 + b1 - 1), b1);
- }
-
- /** SQL <code>CEIL</code> operator applied to short values. */
- public static short ceil(short b0, short b1) {
- return floor((short) (b0 + b1 - 1), b1);
- }
-
- /** SQL <code>CEIL</code> operator applied to int values. */
- public static int ceil(int b0, int b1) {
- int r = b0 % b1;
- if (r > 0) {
- r -= b1;
- }
- return b0 - r;
- }
-
- /** SQL <code>CEIL</code> operator applied to long values. */
- public static long ceil(long b0, long b1) {
- return floor(b0 + b1 - 1, b1);
- }
-
- // temporary
- public static BigDecimal ceil(BigDecimal b0, int b1) {
- return ceil(b0, BigDecimal.valueOf(b1));
- }
-
- // temporary
- public static int ceil(int b0, BigDecimal b1) {
- return ceil(b0, b1.intValue());
- }
-
- public static BigDecimal ceil(BigDecimal b0, BigDecimal b1) {
- final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1);
- BigDecimal r = bigDecimals[1];
- if (r.signum() > 0) {
- r = r.subtract(b1);
- }
- return b0.subtract(r);
- }
-
- // ABS
-
- /** SQL <code>ABS</code> operator applied to byte values. */
- public static byte abs(byte b0) {
- return (byte) Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to short values. */
- public static short abs(short b0) {
- return (short) Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to int values. */
- public static int abs(int b0) {
- return Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to long values. */
- public static long abs(long b0) {
- return Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to float values. */
- public static float abs(float b0) {
- return Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to double values. */
- public static double abs(double b0) {
- return Math.abs(b0);
- }
-
- /** SQL <code>ABS</code> operator applied to BigDecimal values. */
- public static BigDecimal abs(BigDecimal b0) {
- return b0.abs();
- }
-
- // ACOS
- /** SQL <code>ACOS</code> operator applied to long values. */
- public static double acos(long b0) {
- return Math.acos(b0);
- }
-
- /** SQL <code>ACOS</code> operator applied to BigDecimal values. */
- public static double acos(BigDecimal b0) {
- return Math.acos(b0.doubleValue());
- }
-
- /** SQL <code>ACOS</code> operator applied to double values. */
- public static double acos(double b0) {
- return Math.acos(b0);
- }
-
- // ASIN
- /** SQL <code>ASIN</code> operator applied to long values. */
- public static double asin(long b0) {
- return Math.asin(b0);
- }
-
- /** SQL <code>ASIN</code> operator applied to BigDecimal values. */
- public static double asin(BigDecimal b0) {
- return Math.asin(b0.doubleValue());
- }
-
- /** SQL <code>ASIN</code> operator applied to double values. */
- public static double asin(double b0) {
- return Math.asin(b0);
- }
-
- // ATAN
- /** SQL <code>ATAN</code> operator applied to long values. */
- public static double atan(long b0) {
- return Math.atan(b0);
- }
-
- /** SQL <code>ATAN</code> operator applied to BigDecimal values. */
- public static double atan(BigDecimal b0) {
- return Math.atan(b0.doubleValue());
- }
-
- /** SQL <code>ATAN</code> operator applied to double values. */
- public static double atan(double b0) {
- return Math.atan(b0);
- }
-
- // ATAN2
- /** SQL <code>ATAN2</code> operator applied to long values. */
- public static double atan2(long b0, long b1) {
- return Math.atan2(b0, b1);
- }
-
- /** SQL <code>ATAN2</code> operator applied to long/BigDecimal values. */
- public static double atan2(long b0, BigDecimal b1) {
- return Math.atan2(b0, b1.doubleValue());
- }
-
- /** SQL <code>ATAN2</code> operator applied to BigDecimal values. */
- public static double atan2(BigDecimal b0, BigDecimal b1) {
- return Math.atan2(b0.doubleValue(), b1.doubleValue());
- }
-
- /** SQL <code>ATAN2</code> operator applied to double values. */
- public static double atan2(double b0, double b1) {
- return Math.atan2(b0, b1);
- }
-
- // COS
- /** SQL <code>COS</code> operator applied to long values. */
- public static double cos(long b0) {
- return Math.cos(b0);
- }
-
- /** SQL <code>COS</code> operator applied to BigDecimal values. */
- public static double cos(BigDecimal b0) {
- return Math.cos(b0.doubleValue());
- }
-
- /** SQL <code>COS</code> operator applied to double values. */
- public static double cos(double b0) {
- return Math.cos(b0);
- }
-
- // COT
- /** SQL <code>COT</code> operator applied to long values. */
- public static double cot(long b0) {
- return 1.0d / Math.tan(b0);
- }
-
- /** SQL <code>COT</code> operator applied to BigDecimal values. */
- public static double cot(BigDecimal b0) {
- return 1.0d / Math.tan(b0.doubleValue());
- }
-
- /** SQL <code>COT</code> operator applied to double values. */
- public static double cot(double b0) {
- return 1.0d / Math.tan(b0);
- }
-
- // DEGREES
- /** SQL <code>DEGREES</code> operator applied to long values. */
- public static double degrees(long b0) {
- return Math.toDegrees(b0);
- }
-
- /** SQL <code>DEGREES</code> operator applied to BigDecimal values. */
- public static double degrees(BigDecimal b0) {
- return Math.toDegrees(b0.doubleValue());
- }
-
- /** SQL <code>DEGREES</code> operator applied to double values. */
- public static double degrees(double b0) {
- return Math.toDegrees(b0);
- }
-
- // RADIANS
- /** SQL <code>RADIANS</code> operator applied to long values. */
- public static double radians(long b0) {
- return Math.toRadians(b0);
- }
-
- /** SQL <code>RADIANS</code> operator applied to BigDecimal values. */
- public static double radians(BigDecimal b0) {
- return Math.toRadians(b0.doubleValue());
- }
-
- /** SQL <code>RADIANS</code> operator applied to double values. */
- public static double radians(double b0) {
- return Math.toRadians(b0);
- }
-
- // SQL ROUND
- /** SQL <code>ROUND</code> operator applied to long values. */
- public static int sround(int b0, int b1) {
- return sround(BigDecimal.valueOf(b0), b1).intValue();
- }
-
- /** SQL <code>ROUND</code> operator applied to long values. */
- public static long sround(long b0, int b1) {
- return sround(BigDecimal.valueOf(b0), b1).longValue();
- }
-
- /** SQL <code>ROUND</code> operator applied to BigDecimal values. */
- public static BigDecimal sround(BigDecimal b0, int b1) {
- return b0.movePointRight(b1).setScale(0, RoundingMode.HALF_UP).movePointLeft(b1);
- }
-
- /** SQL <code>ROUND</code> operator applied to double values. */
- public static double sround(double b0, int b1) {
- return sround(BigDecimal.valueOf(b0), b1).doubleValue();
- }
-
- // SQL TRUNCATE
- /** SQL <code>TRUNCATE</code> operator applied to int values. */
- public static int struncate(int b0, int b1) {
- return struncate(BigDecimal.valueOf(b0), b1).intValue();
- }
-
- /** SQL <code>TRUNCATE</code> operator applied to long values. */
- public static long struncate(long b0, int b1) {
- return struncate(BigDecimal.valueOf(b0), b1).longValue();
- }
-
- /** SQL <code>TRUNCATE</code> operator applied to BigDecimal values. */
- public static BigDecimal struncate(BigDecimal b0, int b1) {
- return b0.movePointRight(b1).setScale(0, RoundingMode.DOWN).movePointLeft(b1);
- }
-
- /** SQL <code>TRUNCATE</code> operator applied to double values. */
- public static double struncate(double b0, int b1) {
- return struncate(BigDecimal.valueOf(b0), b1).doubleValue();
- }
-
- // SIGN
- /** SQL <code>SIGN</code> operator applied to int values. */
- public static int sign(int b0) {
- return Integer.signum(b0);
- }
-
- /** SQL <code>SIGN</code> operator applied to long values. */
- public static long sign(long b0) {
- return Long.signum(b0);
- }
-
- /** SQL <code>SIGN</code> operator applied to BigDecimal values. */
- public static BigDecimal sign(BigDecimal b0) {
- return BigDecimal.valueOf(b0.signum());
- }
-
- /** SQL <code>SIGN</code> operator applied to double values. */
- public static double sign(double b0) {
- return Math.signum(b0);
- }
-
- // SIN
- /** SQL <code>SIN</code> operator applied to long values. */
- public static double sin(long b0) {
- return Math.sin(b0);
- }
-
- /** SQL <code>SIN</code> operator applied to BigDecimal values. */
- public static double sin(BigDecimal b0) {
- return Math.sin(b0.doubleValue());
- }
-
- /** SQL <code>SIN</code> operator applied to double values. */
- public static double sin(double b0) {
- return Math.sin(b0);
- }
-
- // TAN
- /** SQL <code>TAN</code> operator applied to long values. */
- public static double tan(long b0) {
- return Math.tan(b0);
- }
-
- /** SQL <code>TAN</code> operator applied to BigDecimal values. */
- public static double tan(BigDecimal b0) {
- return Math.tan(b0.doubleValue());
- }
-
- /** SQL <code>TAN</code> operator applied to double values. */
- public static double tan(double b0) {
- return Math.tan(b0);
- }
-
- // Helpers
-
- /** Helper for implementing MIN. Somewhat similar to LEAST operator. */
- public static <T extends Comparable<T>> T lesser(T b0, T b1) {
- return b0 == null || b0.compareTo(b1) > 0 ? b1 : b0;
- }
-
- /** LEAST operator. */
- public static <T extends Comparable<T>> T least(T b0, T b1) {
- return b0 == null || b1 != null && b0.compareTo(b1) > 0 ? b1 : b0;
- }
-
- public static boolean greater(boolean b0, boolean b1) {
- return b0 || b1;
- }
-
- public static boolean lesser(boolean b0, boolean b1) {
- return b0 && b1;
- }
-
- public static byte greater(byte b0, byte b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static byte lesser(byte b0, byte b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static char greater(char b0, char b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static char lesser(char b0, char b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static short greater(short b0, short b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static short lesser(short b0, short b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static int greater(int b0, int b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static int lesser(int b0, int b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static long greater(long b0, long b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static long lesser(long b0, long b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static float greater(float b0, float b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static float lesser(float b0, float b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- public static double greater(double b0, double b1) {
- return b0 > b1 ? b0 : b1;
- }
-
- public static double lesser(double b0, double b1) {
- return b0 > b1 ? b1 : b0;
- }
-
- /** Helper for implementing MAX. Somewhat similar to GREATEST operator. */
- public static <T extends Comparable<T>> T greater(T b0, T b1) {
- return b0 == null || b0.compareTo(b1) < 0 ? b1 : b0;
- }
-
- /** GREATEST operator. */
- public static <T extends Comparable<T>> T greatest(T b0, T b1) {
- return b0 == null || b1 != null && b0.compareTo(b1) < 0 ? b1 : b0;
- }
-
- /** Boolean comparison. */
- public static int compare(boolean x, boolean y) {
- return x == y ? 0 : x ? 1 : -1;
- }
-
- /** CAST(FLOAT AS VARCHAR). */
- public static String toString(float x) {
- if (x == 0) {
- return "0E0";
- }
- BigDecimal bigDecimal = new BigDecimal(x, MathContext.DECIMAL32).stripTrailingZeros();
- final String s = bigDecimal.toString();
- return s.replaceAll("0*E", "E").replace("E+", "E");
- }
-
- /** CAST(DOUBLE AS VARCHAR). */
- public static String toString(double x) {
- if (x == 0) {
- return "0E0";
- }
- BigDecimal bigDecimal = new BigDecimal(x, MathContext.DECIMAL64).stripTrailingZeros();
- final String s = bigDecimal.toString();
- return s.replaceAll("0*E", "E").replace("E+", "E");
- }
-
- /** CAST(DECIMAL AS VARCHAR). */
- public static String toString(BigDecimal x) {
- final String s = x.toString();
- if (s.startsWith("0")) {
- // we want ".1" not "0.1"
- return s.substring(1);
- } else if (s.startsWith("-0")) {
- // we want "-.1" not "-0.1"
- return "-" + s.substring(2);
- } else {
- return s;
- }
- }
-
- /** CAST(BOOLEAN AS VARCHAR). */
- public static String toString(boolean x) {
- // Boolean.toString returns lower case -- no good.
- return x ? "TRUE" : "FALSE";
- }
-
- @NonDeterministic
- private static Object cannotConvert(Object o, Class toType) {
- throw new RuntimeException("Cannot convert " + o + " to " + toType);
- }
-
- /** CAST(VARCHAR AS BOOLEAN). */
- public static boolean toBoolean(String s) {
- s = trim_(s, true, true, ' ');
- if (s.equalsIgnoreCase("TRUE")) {
- return true;
- } else if (s.equalsIgnoreCase("FALSE")) {
- return false;
- } else {
- throw new RuntimeException("Invalid character for cast");
- }
- }
-
- public static boolean toBoolean(Number number) {
- return !number.equals(0);
- }
-
- public static boolean toBoolean(Object o) {
- return o instanceof Boolean ? (Boolean) o
- : o instanceof Number ? toBoolean((Number) o)
- : o instanceof String ? toBoolean((String) o) : (Boolean) cannotConvert(o, boolean.class);
- }
-
- // Don't need parseByte etc. - Byte.parseByte is sufficient.
-
- public static byte toByte(Object o) {
- return o instanceof Byte ? (Byte) o : o instanceof Number ? toByte((Number) o) : Byte.parseByte(o.toString());
- }
-
- public static byte toByte(Number number) {
- return number.byteValue();
- }
-
- public static char toChar(String s) {
- return s.charAt(0);
- }
-
- public static Character toCharBoxed(String s) {
- return s.charAt(0);
- }
-
- public static short toShort(String s) {
- return Short.parseShort(s.trim());
- }
-
- public static short toShort(Number number) {
- return number.shortValue();
- }
-
- public static short toShort(Object o) {
- return o instanceof Short ? (Short) o
- : o instanceof Number ? toShort((Number) o)
- : o instanceof String ? toShort((String) o) : (Short) cannotConvert(o, short.class);
- }
-
- /** Converts the Java type used for UDF parameters of SQL DATE type
- * ({@link java.sql.Date}) to internal representation (int).
- *
- * <p>Converse of {@link #internalToDate(int)}. */
- public static int toInt(java.util.Date v) {
- return toInt(v, LOCAL_TZ);
- }
-
- public static int toInt(java.util.Date v, TimeZone timeZone) {
- return (int) (toLong(v, timeZone) / DateTimeUtils.MILLIS_PER_DAY);
- }
-
- public static Integer toIntOptional(java.util.Date v) {
- return v == null ? null : toInt(v);
- }
-
- public static Integer toIntOptional(java.util.Date v, TimeZone timeZone) {
- return v == null ? null : toInt(v, timeZone);
- }
-
- public static long toLong(Date v) {
- return toLong(v, LOCAL_TZ);
- }
-
- /** Converts the Java type used for UDF parameters of SQL TIME type
- * ({@link java.sql.Time}) to internal representation (int).
- *
- * <p>Converse of {@link #internalToTime(int)}. */
- public static int toInt(java.sql.Time v) {
- return (int) (toLong(v) % DateTimeUtils.MILLIS_PER_DAY);
- }
-
- public static Integer toIntOptional(java.sql.Time v) {
- return v == null ? null : toInt(v);
- }
-
- public static int toInt(String s) {
- return Integer.parseInt(s.trim());
- }
-
- public static int toInt(Number number) {
- return number.intValue();
- }
-
- public static int toInt(Object o) {
- return o instanceof Integer ? (Integer) o
- : o instanceof Number ? toInt((Number) o)
- : o instanceof String ? toInt((String) o)
- : o instanceof java.util.Date ? toInt((java.util.Date) o)
- : (Integer) cannotConvert(o, int.class);
- }
-
- /** Converts the Java type used for UDF parameters of SQL TIMESTAMP type
- * ({@link java.sql.Timestamp}) to internal representation (long).
- *
- * <p>Converse of {@link #internalToTimestamp(long)}. */
- public static long toLong(Timestamp v) {
- return toLong(v, LOCAL_TZ);
- }
-
- // mainly intended for java.sql.Timestamp but works for other dates also
- public static long toLong(java.util.Date v, TimeZone timeZone) {
- final long time = v.getTime();
- return time + timeZone.getOffset(time);
- }
-
- // mainly intended for java.sql.Timestamp but works for other dates also
- public static Long toLongOptional(java.util.Date v) {
- return v == null ? null : toLong(v, LOCAL_TZ);
- }
-
- public static Long toLongOptional(Timestamp v, TimeZone timeZone) {
- if (v == null) {
- return null;
- }
- return toLong(v, LOCAL_TZ);
- }
-
- public static long toLong(String s) {
- if (s.startsWith("199") && s.contains(":")) {
- return Timestamp.valueOf(s).getTime();
- }
- return Long.parseLong(s.trim());
- }
-
- public static long toLong(Number number) {
- return number.longValue();
- }
-
- public static long toLong(Object o) {
- return o instanceof Long ? (Long) o
- : o instanceof Number ? toLong((Number) o)
- : o instanceof String ? toLong((String) o) : (Long) cannotConvert(o, long.class);
- }
-
- public static float toFloat(String s) {
- return Float.parseFloat(s.trim());
- }
-
- public static float toFloat(Number number) {
- return number.floatValue();
- }
-
- public static float toFloat(Object o) {
- return o instanceof Float ? (Float) o
- : o instanceof Number ? toFloat((Number) o)
- : o instanceof String ? toFloat((String) o) : (Float) cannotConvert(o, float.class);
- }
-
- public static double toDouble(String s) {
- return Double.parseDouble(s.trim());
- }
-
- public static double toDouble(Number number) {
- return number.doubleValue();
- }
-
- public static double toDouble(Object o) {
- return o instanceof Double ? (Double) o
- : o instanceof Number ? toDouble((Number) o)
- : o instanceof String ? toDouble((String) o) : (Double) cannotConvert(o, double.class);
- }
-
- public static BigDecimal toBigDecimal(String s) {
- return new BigDecimal(s.trim());
- }
-
- public static BigDecimal toBigDecimal(Number number) {
- // There are some values of "long" that cannot be represented as "double".
- // Not so "int". If it isn't a long, go straight to double.
- return number instanceof BigDecimal ? (BigDecimal) number
- : number instanceof BigInteger ? new BigDecimal((BigInteger) number)
- : number instanceof Long ? new BigDecimal(number.longValue())
- : new BigDecimal(number.doubleValue());
- }
-
- public static BigDecimal toBigDecimal(Object o) {
- return o instanceof Number ? toBigDecimal((Number) o) : toBigDecimal(o.toString());
- }
-
- /** Converts the internal representation of a SQL DATE (int) to the Java
- * type used for UDF parameters ({@link java.sql.Date}). */
- public static java.sql.Date internalToDate(int v) {
- final long t = v * DateTimeUtils.MILLIS_PER_DAY;
- return new java.sql.Date(t - LOCAL_TZ.getOffset(t));
- }
-
- /** As {@link #internalToDate(int)} but allows nulls. */
- public static java.sql.Date internalToDate(Integer v) {
- return v == null ? null : internalToDate(v.intValue());
- }
-
- /** Converts the internal representation of a SQL TIME (int) to the Java
- * type used for UDF parameters ({@link java.sql.Time}). */
- public static java.sql.Time internalToTime(int v) {
- return new java.sql.Time(v - LOCAL_TZ.getOffset(v));
- }
-
- public static java.sql.Time internalToTime(Integer v) {
- return v == null ? null : internalToTime(v.intValue());
- }
-
- /** Converts the internal representation of a SQL TIMESTAMP (long) to the Java
- * type used for UDF parameters ({@link java.sql.Timestamp}). */
- public static java.sql.Timestamp internalToTimestamp(long v) {
- return new java.sql.Timestamp(v - LOCAL_TZ.getOffset(v));
- }
-
- public static java.sql.Timestamp internalToTimestamp(Long v) {
- return v == null ? null : internalToTimestamp(v.longValue());
- }
-
- // Don't need shortValueOf etc. - Short.valueOf is sufficient.
-
- /** Helper for CAST(... AS VARCHAR(maxLength)). */
- public static String truncate(String s, int maxLength) {
- if (s == null) {
- return null;
- } else if (s.length() > maxLength) {
- return s.substring(0, maxLength);
- } else {
- return s;
- }
- }
-
- /** Helper for CAST(... AS CHAR(maxLength)). */
- public static String truncateOrPad(String s, int maxLength) {
- if (s == null) {
- return null;
- } else {
- final int length = s.length();
- if (length > maxLength) {
- return s.substring(0, maxLength);
- } else {
- return length < maxLength ? Spaces.padRight(s, maxLength) : s;
- }
- }
- }
-
- /** Helper for CAST(... AS VARBINARY(maxLength)). */
- public static ByteString truncate(ByteString s, int maxLength) {
- if (s == null) {
- return null;
- } else if (s.length() > maxLength) {
- return s.substring(0, maxLength);
- } else {
- return s;
- }
- }
-
- /** Helper for CAST(... AS BINARY(maxLength)). */
- public static ByteString truncateOrPad(ByteString s, int maxLength) {
- if (s == null) {
- return null;
- } else {
- final int length = s.length();
- if (length > maxLength) {
- return s.substring(0, maxLength);
- } else if (length < maxLength) {
- return s.concat(new ByteString(new byte[maxLength - length]));
- } else {
- return s;
- }
- }
- }
-
- /** SQL {@code POSITION(seek IN string)} function. */
- public static int position(String seek, String s) {
- return s.indexOf(seek) + 1;
- }
-
- /** SQL {@code POSITION(seek IN string)} function for byte strings. */
- public static int position(ByteString seek, ByteString s) {
- return s.indexOf(seek) + 1;
- }
-
- /** SQL {@code POSITION(seek IN string FROM integer)} function. */
- public static int position(String seek, String s, int from) {
- final int from0 = from - 1; // 0-based
- if (from0 > s.length() || from0 < 0) {
- return 0;
- }
-
- return s.indexOf(seek, from0) + 1;
- }
-
- /** SQL {@code POSITION(seek IN string FROM integer)} function for byte
- * strings. */
- public static int position(ByteString seek, ByteString s, int from) {
- final int from0 = from - 1;
- if (from0 > s.length() || from0 < 0) {
- return 0;
- }
-
- // ByteString doesn't have indexOf(ByteString, int) until avatica-1.9
- // (see [CALCITE-1423]), so apply substring and find from there.
- Bug.upgrade("in avatica-1.9, use ByteString.substring(ByteString, int)");
- final int p = s.substring(from0).indexOf(seek);
- if (p < 0) {
- return 0;
- }
- return p + from;
- }
-
- /** Helper for rounding. Truncate(12345, 1000) returns 12000. */
- public static long round(long v, long x) {
- return truncate(v + x / 2, x);
- }
-
- /** Helper for rounding. Truncate(12345, 1000) returns 12000. */
- public static long truncate(long v, long x) {
- long remainder = v % x;
- if (remainder < 0) {
- remainder += x;
- }
- return v - remainder;
- }
-
- /** Helper for rounding. Truncate(12345, 1000) returns 12000. */
- public static int round(int v, int x) {
- return truncate(v + x / 2, x);
- }
-
- /** Helper for rounding. Truncate(12345, 1000) returns 12000. */
- public static int truncate(int v, int x) {
- int remainder = v % x;
- if (remainder < 0) {
- remainder += x;
- }
- return v - remainder;
- }
-
- /** SQL {@code CURRENT_TIMESTAMP} function. */
- @NonDeterministic
- public static long currentTimestamp(DataContext root) {
- // Cast required for JDK 1.6.
- return (Long) DataContext.Variable.CURRENT_TIMESTAMP.get(root);
- }
-
- /** SQL {@code CURRENT_TIME} function. */
- @NonDeterministic
- public static int currentTime(DataContext root) {
- int time = (int) (currentTimestamp(root) % DateTimeUtils.MILLIS_PER_DAY);
- if (time < 0) {
- time += DateTimeUtils.MILLIS_PER_DAY;
- }
- return time;
- }
-
- /** SQL {@code CURRENT_DATE} function. */
- @NonDeterministic
- public static int currentDate(DataContext root) {
- final long timestamp = currentTimestamp(root);
- int date = (int) (timestamp / DateTimeUtils.MILLIS_PER_DAY);
- final int time = (int) (timestamp % DateTimeUtils.MILLIS_PER_DAY);
- if (time < 0) {
- --date;
- }
- return date;
- }
-
- /** SQL {@code LOCAL_TIMESTAMP} function. */
- @NonDeterministic
- public static long localTimestamp(DataContext root) {
- // Cast required for JDK 1.6.
- return (Long) DataContext.Variable.LOCAL_TIMESTAMP.get(root);
- }
-
- /** SQL {@code LOCAL_TIME} function. */
- @NonDeterministic
- public static int localTime(DataContext root) {
- return (int) (localTimestamp(root) % DateTimeUtils.MILLIS_PER_DAY);
- }
-
- /** SQL {@code TRANSLATE(string, search_chars, replacement_chars)}
- * function. */
- public static String translate3(String s, String search, String replacement) {
- return org.apache.commons.lang3.StringUtils.replaceChars(s, search, replacement);
- }
-
- /** SQL {@code REPLACE(string, search, replacement)} function. */
- public static String replace(String s, String search, String replacement) {
- return s.replace(search, replacement);
- }
-
- /** Helper for "array element reference". Caller has already ensured that
- * array and index are not null. Index is 1-based, per SQL. */
- public static Object arrayItem(List list, int item) {
- if (item < 1 || item > list.size()) {
- return null;
- }
- return list.get(item - 1);
- }
-
- /** Helper for "map element reference". Caller has already ensured that
- * array and index are not null. Index is 1-based, per SQL. */
- public static Object mapItem(Map map, Object item) {
- return map.get(item);
- }
-
- /** Implements the {@code [ ... ]} operator on an object whose type is not
- * known until runtime.
- */
- public static Object item(Object object, Object index) {
- if (object instanceof Map) {
- return mapItem((Map) object, index);
- }
- if (object instanceof List && index instanceof Number) {
- return arrayItem((List) object, ((Number) index).intValue());
- }
- return null;
- }
-
- /** As {@link #arrayItem} method, but allows array to be nullable. */
- public static Object arrayItemOptional(List list, int item) {
- if (list == null) {
- return null;
- }
- return arrayItem(list, item);
- }
-
- /** As {@link #mapItem} method, but allows map to be nullable. */
- public static Object mapItemOptional(Map map, Object item) {
- if (map == null) {
- return null;
- }
- return mapItem(map, item);
- }
-
- /** As {@link #item} method, but allows object to be nullable. */
- public static Object itemOptional(Object object, Object index) {
- if (object == null) {
- return null;
- }
- return item(object, index);
- }
-
- /** NULL → FALSE, FALSE → FALSE, TRUE → TRUE. */
- public static boolean isTrue(Boolean b) {
- return b != null && b;
- }
-
- /** NULL → FALSE, FALSE → TRUE, TRUE → FALSE. */
- public static boolean isFalse(Boolean b) {
- return b != null && !b;
- }
-
- /** NULL → TRUE, FALSE → TRUE, TRUE → FALSE. */
- public static boolean isNotTrue(Boolean b) {
- return b == null || !b;
- }
-
- /** NULL → TRUE, FALSE → FALSE, TRUE → TRUE. */
- public static boolean isNotFalse(Boolean b) {
- return b == null || b;
- }
-
- /** NULL → NULL, FALSE → TRUE, TRUE → FALSE. */
- public static Boolean not(Boolean b) {
- return (b == null) ? null : !b;
- }
-
- /** Converts a JDBC array to a list. */
- public static List arrayToList(final java.sql.Array a) {
- if (a == null) {
- return null;
- }
- try {
- return Primitive.asList(a.getArray());
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Support the {@code CURRENT VALUE OF sequence} operator. */
- @NonDeterministic
- public static long sequenceCurrentValue(String key) {
- return getAtomicLong(key).get();
- }
-
- /** Support the {@code NEXT VALUE OF sequence} operator. */
- @NonDeterministic
- public static long sequenceNextValue(String key) {
- return getAtomicLong(key).incrementAndGet();
- }
-
- private static AtomicLong getAtomicLong(String key) {
- final Map<String, AtomicLong> map = THREAD_SEQUENCES.get();
- AtomicLong atomic = map.get(key);
- if (atomic == null) {
- atomic = new AtomicLong();
- map.put(key, atomic);
- }
- return atomic;
- }
-
- /** Support the SLICE function. */
- public static List slice(List list) {
- return list;
- }
-
- /** Support the ELEMENT function. */
- public static Object element(List list) {
- switch (list.size()) {
- case 0:
- return null;
- case 1:
- return list.get(0);
- default:
- throw new RuntimeException("more than one value");
- }
- }
-
- public static Function1<Object, Enumerable<ComparableList<Comparable>>> flatProduct(final int[] fieldCounts,
- final boolean withOrdinality, final FlatProductInputType[] inputTypes) {
- if (fieldCounts.length == 1) {
- if (!withOrdinality && inputTypes[0] == FlatProductInputType.SCALAR) {
- //noinspection unchecked
- return (Function1) LIST_AS_ENUMERABLE;
- } else {
- return new Function1<Object, Enumerable<ComparableList<Comparable>>>() {
- public Enumerable<ComparableList<Comparable>> apply(Object row) {
- return p2(new Object[] { row }, fieldCounts, withOrdinality, inputTypes);
- }
- };
- }
- }
- return new Function1<Object, Enumerable<FlatLists.ComparableList<Comparable>>>() {
- public Enumerable<FlatLists.ComparableList<Comparable>> apply(Object lists) {
- return p2((Object[]) lists, fieldCounts, withOrdinality, inputTypes);
- }
- };
- }
-
- private static Enumerable<FlatLists.ComparableList<Comparable>> p2(Object[] lists, int[] fieldCounts,
- boolean withOrdinality, FlatProductInputType[] inputTypes) {
- final List<Enumerator<List<Comparable>>> enumerators = new ArrayList<>();
- int totalFieldCount = 0;
- for (int i = 0; i < lists.length; i++) {
- int fieldCount = fieldCounts[i];
- FlatProductInputType inputType = inputTypes[i];
- Object inputObject = lists[i];
- switch (inputType) {
- case SCALAR:
- @SuppressWarnings("unchecked")
- List<Comparable> list = (List<Comparable>) inputObject;
- enumerators
- .add(Linq4j.transform(Linq4j.enumerator(list), new Function1<Comparable, List<Comparable>>() {
- public List<Comparable> apply(Comparable a0) {
- return FlatLists.of(a0);
- }
- }));
- break;
- case LIST:
- @SuppressWarnings("unchecked")
- List<List<Comparable>> listList = (List<List<Comparable>>) inputObject;
- enumerators.add(Linq4j.enumerator(listList));
- break;
- case MAP:
- @SuppressWarnings("unchecked")
- Map<Comparable, Comparable> map = (Map<Comparable, Comparable>) inputObject;
- Enumerator<Entry<Comparable, Comparable>> enumerator = Linq4j.enumerator(map.entrySet());
-
- Enumerator<List<Comparable>> transformed = Linq4j.transform(enumerator,
- new Function1<Entry<Comparable, Comparable>, List<Comparable>>() {
- public List<Comparable> apply(Entry<Comparable, Comparable> entry) {
- return FlatLists.<Comparable> of(entry.getKey(), entry.getValue());
- }
- });
- enumerators.add(transformed);
- break;
- default:
- break;
- }
- if (fieldCount < 0) {
- ++totalFieldCount;
- } else {
- totalFieldCount += fieldCount;
- }
- }
- if (withOrdinality) {
- ++totalFieldCount;
- }
- return product(enumerators, totalFieldCount, withOrdinality);
- }
-
- public static Object[] array(Object... args) {
- return args;
- }
-
- /** Similar to {@link Linq4j#product(Iterable)} but each resulting list
- * implements {@link FlatLists.ComparableList}. */
- public static <E extends Comparable> Enumerable<FlatLists.ComparableList<E>> product(
- final List<Enumerator<List<E>>> enumerators, final int fieldCount, final boolean withOrdinality) {
- return new AbstractEnumerable<FlatLists.ComparableList<E>>() {
- public Enumerator<FlatLists.ComparableList<E>> enumerator() {
- return new ProductComparableListEnumerator<>(enumerators, fieldCount, withOrdinality);
- }
- };
- }
-
- /** Adds a given number of months to a timestamp, represented as the number
- * of milliseconds since the epoch. */
- public static long addMonths(long timestamp, int m) {
- final long millis = DateTimeUtils.floorMod(timestamp, DateTimeUtils.MILLIS_PER_DAY);
- timestamp -= millis;
- final long x = addMonths((int) (timestamp / DateTimeUtils.MILLIS_PER_DAY), m);
- return x * DateTimeUtils.MILLIS_PER_DAY + millis;
- }
-
- /** Adds a given number of months to a date, represented as the number of
- * days since the epoch. */
- //override
- public static int addMonths(int date, int m) {
- int y0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.YEAR, date);
- int m0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.MONTH, date);
- int d0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.DAY, date);
- int y = (m + m0) / 12;
- y0 += y;
- m0 = m + m0 - y * 12;
- if (m0 <= 0) {
- m0 += 12;
- assert m0 > 0;
- y0--;
- }
- int last = lastDay(y0, m0);
- if (d0 > last) {
- d0 = last;
- }
- return DateTimeUtils.ymdToUnixDate(y0, m0, d0);
- }
-
- private static int lastDay(int y, int m) {
- switch (m) {
- case 2:
- return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
- case 4:
- case 6:
- case 9:
- case 11:
- return 30;
- default:
- return 31;
- }
- }
-
- /** Finds the number of months between two dates, each represented as the
- * number of days since the epoch. */
- public static int subtractMonths(int date0, int date1) {
- if (date0 < date1) {
- return -subtractMonths(date1, date0);
- }
- // Start with an estimate.
- // Since no month has more than 31 days, the estimate is <= the true value.
- int m = (date0 - date1) / 31;
- for (;;) {
- int date2 = addMonths(date1, m);
- if (date2 >= date0) {
- return m;
- }
- int date3 = addMonths(date1, m + 1);
- if (date3 > date0) {
- return m;
- }
- ++m;
- }
- }
-
- public static int subtractMonths(long t0, long t1) {
- final long millis0 = DateTimeUtils.floorMod(t0, DateTimeUtils.MILLIS_PER_DAY);
- final int d0 = (int) DateTimeUtils.floorDiv(t0 - millis0, DateTimeUtils.MILLIS_PER_DAY);
- final long millis1 = DateTimeUtils.floorMod(t1, DateTimeUtils.MILLIS_PER_DAY);
- final int d1 = (int) DateTimeUtils.floorDiv(t1 - millis1, DateTimeUtils.MILLIS_PER_DAY);
- int x = subtractMonths(d0, d1);
- final long d2 = addMonths(d1, x);
- if (d2 == d0 && millis0 < millis1) {
- --x;
- }
- return x;
- }
-
- /** Enumerates over the cartesian product of the given lists, returning
- * a comparable list for each row. */
- private static class ProductComparableListEnumerator<E extends Comparable>
- extends CartesianProductEnumerator<List<E>, FlatLists.ComparableList<E>> {
- final E[] flatElements;
- final List<E> list;
- private final boolean withOrdinality;
- private int ordinality;
-
- ProductComparableListEnumerator(List<Enumerator<List<E>>> enumerators, int fieldCount, boolean withOrdinality) {
- super(enumerators);
- this.withOrdinality = withOrdinality;
- flatElements = (E[]) new Comparable[fieldCount];
- list = Arrays.asList(flatElements);
- }
-
- public FlatLists.ComparableList<E> current() {
- int i = 0;
- for (Object element : (Object[]) elements) {
- final List list2 = (List) element;
- Object[] a = list2.toArray();
- System.arraycopy(a, 0, flatElements, i, a.length);
- i += a.length;
- }
- if (withOrdinality) {
- flatElements[i] = (E) Integer.valueOf(++ordinality); // 1-based
- }
- return FlatLists.ofComparable(list);
- }
- }
-
- /** Type of argument passed into {@link #flatProduct}. */
- public enum FlatProductInputType {
- SCALAR, LIST, MAP
- }
-
-}
-
-// End SqlFunctions.java
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/atopcalcite/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
deleted file mode 100644
index 320cd7c..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
+++ /dev/null
@@ -1,1336 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.sql.type;
-
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeFamily;
-import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
-import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlCallBinding;
-import org.apache.calcite.sql.SqlCollation;
-import org.apache.calcite.sql.SqlDataTypeSpec;
-import org.apache.calcite.sql.SqlIdentifier;
-import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.util.NumberUtil;
-import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import java.nio.charset.Charset;
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import static org.apache.calcite.util.Static.RESOURCE;
-
-/**
- * Contains utility methods used during SQL validation or type derivation.
- */
-public abstract class SqlTypeUtil {
- //~ Methods ----------------------------------------------------------------
-
- /**
- * Checks whether two types or more are char comparable.
- *
- * @return Returns true if all operands are of char type and if they are
- * comparable, i.e. of the same charset and collation of same charset
- */
- public static boolean isCharTypeComparable(List<RelDataType> argTypes) {
- assert argTypes != null;
- assert argTypes.size() >= 2;
-
- // Filter out ANY elements.
- List<RelDataType> argTypes2 = Lists.newArrayList();
- for (RelDataType t : argTypes) {
- if (!isAny(t)) {
- argTypes2.add(t);
- }
- }
-
- for (Pair<RelDataType, RelDataType> pair : Pair.adjacents(argTypes2)) {
- RelDataType t0 = pair.left;
- RelDataType t1 = pair.right;
-
- if (!inCharFamily(t0) || !inCharFamily(t1)) {
- return false;
- }
-
- if (t0.getCharset() == null) {
- throw new AssertionError("RelDataType object should have been assigned "
- + "a (default) charset when calling deriveType");
- } else if (!t0.getCharset().equals(t1.getCharset())) {
- return false;
- }
-
- if (t0.getCollation() == null) {
- throw new AssertionError("RelDataType object should have been assigned "
- + "a (default) collation when calling deriveType");
- } else if (!t0.getCollation().getCharset().equals(
- t1.getCollation().getCharset())) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns whether the operands to a call are char type-comparable.
- *
- * @param binding Binding of call to operands
- * @param operands Operands to check for compatibility; usually the
- * operands of the bound call, but not always
- * @param throwOnFailure Whether to throw an exception on failure
- * @return whether operands are valid
- */
- public static boolean isCharTypeComparable(
- SqlCallBinding binding,
- List<SqlNode> operands,
- boolean throwOnFailure) {
- final SqlValidator validator = binding.getValidator();
- final SqlValidatorScope scope = binding.getScope();
- assert operands != null;
- assert operands.size() >= 2;
-
- if (!isCharTypeComparable(
- deriveAndCollectTypes(validator, scope, operands))) {
- if (throwOnFailure) {
- String msg = "";
- for (int i = 0; i < operands.size(); i++) {
- if (i > 0) {
- msg += ", ";
- }
- msg += operands.get(i).toString();
- }
- throw binding.newError(RESOURCE.operandNotComparable(msg));
- }
- return false;
- }
- return true;
- }
-
- /**
- * Iterates over all operands, derives their types, and collects them into
- * a list.
- */
- public static List<RelDataType> deriveAndCollectTypes(
- SqlValidator validator,
- SqlValidatorScope scope,
- List<SqlNode> operands) {
- // NOTE: Do not use an AbstractList. Don't want to be lazy. We want
- // errors.
- List<RelDataType> types = new ArrayList<RelDataType>();
- for (SqlNode operand : operands) {
- types.add(validator.deriveType(scope, operand));
- }
- return types;
- }
-
- /**
- * Promotes a type to a row type (does nothing if it already is one).
- *
- * @param type type to be promoted
- * @param fieldName name to give field in row type; null for default of
- * "ROW_VALUE"
- * @return row type
- */
- public static RelDataType promoteToRowType(
- RelDataTypeFactory typeFactory,
- RelDataType type,
- String fieldName) {
- if (!type.isStruct()) {
- if (fieldName == null) {
- fieldName = "ROW_VALUE";
- }
- type = typeFactory.builder().add(fieldName, type).build();
- }
- return type;
- }
-
- /**
- * Recreates a given RelDataType with nullability iff any of the operands
- * of a call are nullable.
- */
- public static RelDataType makeNullableIfOperandsAre(
- final SqlValidator validator,
- final SqlValidatorScope scope,
- final SqlCall call,
- RelDataType type) {
- for (SqlNode operand : call.getOperandList()) {
- RelDataType operandType = validator.deriveType(scope, operand);
-
- if (containsNullable(operandType)) {
- RelDataTypeFactory typeFactory = validator.getTypeFactory();
- type = typeFactory.createTypeWithNullability(type, true);
- break;
- }
- }
- return type;
- }
-
- /**
- * Recreates a given RelDataType with nullability iff any of the param
- * argTypes are nullable.
- */
- public static RelDataType makeNullableIfOperandsAre(
- final RelDataTypeFactory typeFactory,
- final List<RelDataType> argTypes,
- RelDataType type) {
- Preconditions.checkNotNull(type);
- if (containsNullable(argTypes)) {
- type = typeFactory.createTypeWithNullability(type, true);
- }
- return type;
- }
-
- /**
- * Returns whether all of array of types are nullable.
- */
- public static boolean allNullable(List<RelDataType> types) {
- for (RelDataType type : types) {
- if (!containsNullable(type)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns whether one or more of an array of types is nullable.
- */
- public static boolean containsNullable(List<RelDataType> types) {
- for (RelDataType type : types) {
- if (containsNullable(type)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Determines whether a type or any of its fields (if a structured type) are
- * nullable.
- */
- public static boolean containsNullable(RelDataType type) {
- if (type.isNullable()) {
- return true;
- }
- if (!type.isStruct()) {
- return false;
- }
- for (RelDataTypeField field : type.getFieldList()) {
- if (containsNullable(field.getType())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns typeName.equals(type.getSqlTypeName()). If
- * typeName.equals(SqlTypeName.Any) true is always returned.
- */
- public static boolean isOfSameTypeName(
- SqlTypeName typeName,
- RelDataType type) {
- return SqlTypeName.ANY.equals(typeName)
- || typeName.equals(type.getSqlTypeName());
- }
-
- /**
- * Returns true if any element in <code>typeNames</code> matches
- * type.getSqlTypeName().
- *
- * @see #isOfSameTypeName(SqlTypeName, RelDataType)
- */
- public static boolean isOfSameTypeName(
- Collection<SqlTypeName> typeNames,
- RelDataType type) {
- for (SqlTypeName typeName : typeNames) {
- if (isOfSameTypeName(typeName, type)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @return true if type is DATE, TIME, or TIMESTAMP
- */
- public static boolean isDatetime(RelDataType type) {
- return SqlTypeFamily.DATETIME.contains(type);
- }
-
- /**
- * @return true if type is some kind of INTERVAL
- */
- public static boolean isInterval(RelDataType type) {
- return SqlTypeFamily.DATETIME_INTERVAL.contains(type);
- }
-
- /**
- * @return true if type is in SqlTypeFamily.Character
- */
- public static boolean inCharFamily(RelDataType type) {
- return type.getFamily() == SqlTypeFamily.CHARACTER;
- }
-
- /**
- * @return true if type is in SqlTypeFamily.Character
- */
- public static boolean inCharFamily(SqlTypeName typeName) {
- return typeName.getFamily() == SqlTypeFamily.CHARACTER;
- }
-
- /**
- * @return true if type is in SqlTypeFamily.Boolean
- */
- public static boolean inBooleanFamily(RelDataType type) {
- return type.getFamily() == SqlTypeFamily.BOOLEAN;
- }
-
- /**
- * @return true if two types are in same type family
- */
- public static boolean inSameFamily(RelDataType t1, RelDataType t2) {
- return t1.getFamily() == t2.getFamily();
- }
-
- /**
- * @return true if two types are in same type family, or one or the other is
- * of type {@link SqlTypeName#NULL}.
- */
- public static boolean inSameFamilyOrNull(RelDataType t1, RelDataType t2) {
- return (t1.getSqlTypeName() == SqlTypeName.NULL)
- || (t2.getSqlTypeName() == SqlTypeName.NULL)
- || (t1.getFamily() == t2.getFamily());
- }
-
- /**
- * @return true if type family is either character or binary
- */
- public static boolean inCharOrBinaryFamilies(RelDataType type) {
- return (type.getFamily() == SqlTypeFamily.CHARACTER)
- || (type.getFamily() == SqlTypeFamily.BINARY);
- }
-
- /**
- * @return true if type is a LOB of some kind
- */
- public static boolean isLob(RelDataType type) {
- // TODO jvs 9-Dec-2004: once we support LOB types
- return false;
- }
-
- /**
- * @return true if type is variable width with bounded precision
- */
- public static boolean isBoundedVariableWidth(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- switch (typeName) {
- case VARCHAR:
- case VARBINARY:
-
- // TODO angel 8-June-2005: Multiset should be LOB
- case MULTISET:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * @return true if type is one of the integer types
- */
- public static boolean isIntType(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- switch (typeName) {
- case TINYINT:
- case SMALLINT:
- case INTEGER:
- case BIGINT:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * @return true if type is decimal
- */
- public static boolean isDecimal(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- return typeName == SqlTypeName.DECIMAL;
- }
-
- /**
- * @return true if type is bigint
- */
- public static boolean isBigint(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- return typeName == SqlTypeName.BIGINT;
- }
-
- /**
- * @return true if type is numeric with exact precision
- */
- public static boolean isExactNumeric(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- switch (typeName) {
- case TINYINT:
- case SMALLINT:
- case INTEGER:
- case BIGINT:
- case DECIMAL:
- return true;
- default:
- return false;
- }
- }
-
- /** Returns whether a type's scale is set. */
- public static boolean hasScale(RelDataType type) {
- return type.getScale() != Integer.MIN_VALUE;
- }
-
- /**
- * Returns the maximum value of an integral type, as a long value
- */
- public static long maxValue(RelDataType type) {
- assert SqlTypeUtil.isIntType(type);
- switch (type.getSqlTypeName()) {
- case TINYINT:
- return Byte.MAX_VALUE;
- case SMALLINT:
- return Short.MAX_VALUE;
- case INTEGER:
- return Integer.MAX_VALUE;
- case BIGINT:
- return Long.MAX_VALUE;
- default:
- throw Util.unexpected(type.getSqlTypeName());
- }
- }
-
- /**
- * @return true if type is numeric with approximate precision
- */
- public static boolean isApproximateNumeric(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
- switch (typeName) {
- case FLOAT:
- case REAL:
- case DOUBLE:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * @return true if type is numeric
- */
- public static boolean isNumeric(RelDataType type) {
- return isExactNumeric(type) || isApproximateNumeric(type);
- }
-
- /**
- * Tests whether two types have the same name and structure, possibly with
- * differing modifiers. For example, VARCHAR(1) and VARCHAR(10) are
- * considered the same, while VARCHAR(1) and CHAR(1) are considered
- * different. Likewise, VARCHAR(1) MULTISET and VARCHAR(10) MULTISET are
- * considered the same.
- *
- * @return true if types have same name and structure
- */
- public static boolean sameNamedType(RelDataType t1, RelDataType t2) {
- if (t1.isStruct() || t2.isStruct()) {
- if (!t1.isStruct() || !t2.isStruct()) {
- return false;
- }
- if (t1.getFieldCount() != t2.getFieldCount()) {
- return false;
- }
- List<RelDataTypeField> fields1 = t1.getFieldList();
- List<RelDataTypeField> fields2 = t2.getFieldList();
- for (int i = 0; i < fields1.size(); ++i) {
- if (!sameNamedType(
- fields1.get(i).getType(),
- fields2.get(i).getType())) {
- return false;
- }
- }
- return true;
- }
- RelDataType comp1 = t1.getComponentType();
- RelDataType comp2 = t2.getComponentType();
- if ((comp1 != null) || (comp2 != null)) {
- if ((comp1 == null) || (comp2 == null)) {
- return false;
- }
- if (!sameNamedType(comp1, comp2)) {
- return false;
- }
- }
- return t1.getSqlTypeName() == t2.getSqlTypeName();
- }
-
- /**
- * Computes the maximum number of bytes required to represent a value of a
- * type having user-defined precision. This computation assumes no overhead
- * such as length indicators and NUL-terminators. Complex types for which
- * multiple representations are possible (e.g. DECIMAL or TIMESTAMP) return
- * 0.
- *
- * @param type type for which to compute storage
- * @return maximum bytes, or 0 for a fixed-width type or type with unknown
- * maximum
- */
- public static int getMaxByteSize(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
-
- if (typeName == null) {
- return 0;
- }
-
- switch (typeName) {
- case CHAR:
- case VARCHAR:
- return (int) Math.ceil(
- ((double) type.getPrecision())
- * type.getCharset().newEncoder().maxBytesPerChar());
-
- case BINARY:
- case VARBINARY:
- return type.getPrecision();
-
- case MULTISET:
-
- // TODO Wael Jan-24-2005: Need a better way to tell fennel this
- // number. This a very generic place and implementation details like
- // this doesnt belong here. Waiting to change this once we have blob
- // support
- return 4096;
-
- default:
- return 0;
- }
- }
-
- /**
- * Determines the minimum unscaled value of a numeric type
- *
- * @param type a numeric type
- */
- public static long getMinValue(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- switch (typeName) {
- case TINYINT:
- return Byte.MIN_VALUE;
- case SMALLINT:
- return Short.MIN_VALUE;
- case INTEGER:
- return Integer.MIN_VALUE;
- case BIGINT:
- case DECIMAL:
- return NumberUtil.getMinUnscaled(type.getPrecision()).longValue();
- default:
- throw new AssertionError("getMinValue(" + typeName + ")");
- }
- }
-
- /**
- * Determines the maximum unscaled value of a numeric type
- *
- * @param type a numeric type
- */
- public static long getMaxValue(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- switch (typeName) {
- case TINYINT:
- return Byte.MAX_VALUE;
- case SMALLINT:
- return Short.MAX_VALUE;
- case INTEGER:
- return Integer.MAX_VALUE;
- case BIGINT:
- case DECIMAL:
- return NumberUtil.getMaxUnscaled(type.getPrecision()).longValue();
- default:
- throw new AssertionError("getMaxValue(" + typeName + ")");
- }
- }
-
- /**
- * @return true if type has a representation as a Java primitive (ignoring
- * nullability)
- */
- @Deprecated // to be removed before 2.0
- public static boolean isJavaPrimitive(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return false;
- }
-
- switch (typeName) {
- case BOOLEAN:
- case TINYINT:
- case SMALLINT:
- case INTEGER:
- case BIGINT:
- case FLOAT:
- case REAL:
- case DOUBLE:
- case SYMBOL:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * @return class name of the wrapper for the primitive data type.
- */
- @Deprecated // to be removed before 2.0
- public static String getPrimitiveWrapperJavaClassName(RelDataType type) {
- if (type == null) {
- return null;
- }
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return null;
- }
-
- switch (typeName) {
- case BOOLEAN:
- return "Boolean";
- default:
- //noinspection deprecation
- return getNumericJavaClassName(type);
- }
- }
-
- /**
- * @return class name of the numeric data type.
- */
- @Deprecated // to be removed before 2.0
- public static String getNumericJavaClassName(RelDataType type) {
- if (type == null) {
- return null;
- }
- SqlTypeName typeName = type.getSqlTypeName();
- if (typeName == null) {
- return null;
- }
-
- switch (typeName) {
- case TINYINT:
- return "Byte";
- case SMALLINT:
- return "Short";
- case INTEGER:
- return "Integer";
- case BIGINT:
- return "Long";
- case REAL:
- return "Float";
- case DECIMAL:
- case FLOAT:
- case DOUBLE:
- return "Double";
- default:
- return null;
- }
- }
-
- private static boolean isAny(RelDataType t) {
- return t.getFamily() == SqlTypeFamily.ANY;
- }
-
- /**
- * Tests whether a value can be assigned to a site.
- *
- * @param toType type of the target site
- * @param fromType type of the source value
- * @return true iff assignable
- */
- public static boolean canAssignFrom(
- RelDataType toType,
- RelDataType fromType) {
- if (isAny(toType) || isAny(fromType)) {
- return true;
- }
-
- // TODO jvs 2-Jan-2005: handle all the other cases like
- // rows, collections, UDT's
- if (fromType.getSqlTypeName() == SqlTypeName.NULL) {
- // REVIEW jvs 4-Dec-2008: We allow assignment from NULL to any
- // type, including NOT NULL types, since in the case where no
- // rows are actually processed, the assignment is legal
- // (FRG-365). However, it would be better if the validator's
- // NULL type inference guaranteed that we had already
- // assigned a real (nullable) type to every NULL literal.
- return true;
- }
-
- if (fromType.getSqlTypeName() == SqlTypeName.ARRAY) {
- if (toType.getSqlTypeName() != SqlTypeName.ARRAY) {
- return false;
- }
- return canAssignFrom(toType.getComponentType(), fromType.getComponentType());
- }
-
- if (areCharacterSetsMismatched(toType, fromType)) {
- return false;
- }
-
- return toType.getFamily() == fromType.getFamily();
- }
-
- /**
- * Determines whether two types both have different character sets. If one
- * or the other type has no character set (e.g. in cast from INT to
- * VARCHAR), that is not a mismatch.
- *
- * @param t1 first type
- * @param t2 second type
- * @return true iff mismatched
- */
- public static boolean areCharacterSetsMismatched(
- RelDataType t1,
- RelDataType t2) {
- if (isAny(t1) || isAny(t2)) {
- return false;
- }
-
- Charset cs1 = t1.getCharset();
- Charset cs2 = t2.getCharset();
- if ((cs1 != null) && (cs2 != null)) {
- if (!cs1.equals(cs2)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Compares two types and returns true if fromType can be cast to toType.
- *
- * <p>REVIEW jvs 17-Dec-2004: the coerce param below shouldn't really be
- * necessary. We're using it as a hack because
- * {@link SqlTypeFactoryImpl#leastRestrictiveSqlType} isn't complete enough
- * yet. Once it is, this param (and the non-coerce rules of
- * {@link SqlTypeAssignmentRules}) should go away.
- *
- * @param toType target of assignment
- * @param fromType source of assignment
- * @param coerce if true, the SQL rules for CAST are used; if false, the
- * rules are similar to Java; e.g. you can't assign short x =
- * (int) y, and you can't assign int x = (String) z.
- * @return true iff cast is legal
- */
- public static boolean canCastFrom(
- RelDataType toType,
- RelDataType fromType,
- boolean coerce) {
- if (toType == fromType) {
- return true;
- }
- if (isAny(toType) || isAny(fromType)) {
- return true;
- }
-
- final SqlTypeName fromTypeName = fromType.getSqlTypeName();
- final SqlTypeName toTypeName = toType.getSqlTypeName();
- if (toType.isStruct() || fromType.isStruct()) {
- if (toTypeName == SqlTypeName.DISTINCT) {
- if (fromTypeName == SqlTypeName.DISTINCT) {
- // can't cast between different distinct types
- return false;
- }
- return canCastFrom(
- toType.getFieldList().get(0).getType(), fromType, coerce);
- } else if (fromTypeName == SqlTypeName.DISTINCT) {
- return canCastFrom(
- toType, fromType.getFieldList().get(0).getType(), coerce);
- } else if (toTypeName == SqlTypeName.ROW) {
- if (fromTypeName != SqlTypeName.ROW) {
- return false;
- }
- int n = toType.getFieldCount();
- if (fromType.getFieldCount() != n) {
- return false;
- }
- for (int i = 0; i < n; ++i) {
- RelDataTypeField toField = toType.getFieldList().get(i);
- RelDataTypeField fromField = fromType.getFieldList().get(i);
- if (!canCastFrom(
- toField.getType(),
- fromField.getType(),
- coerce)) {
- return false;
- }
- }
- return true;
- } else if (toTypeName == SqlTypeName.MULTISET) {
- if (!fromType.isStruct()) {
- return false;
- }
- if (fromTypeName != SqlTypeName.MULTISET) {
- return false;
- }
- return canCastFrom(
- toType.getComponentType(),
- fromType.getComponentType(),
- coerce);
- } else if (fromTypeName == SqlTypeName.MULTISET) {
- return false;
- } else {
- return toType.getFamily() == fromType.getFamily();
- }
- }
- RelDataType c1 = toType.getComponentType();
- if (c1 != null) {
- RelDataType c2 = fromType.getComponentType();
- if (c2 == null) {
- return false;
- }
- return canCastFrom(c1, c2, coerce);
- }
- if ((isInterval(fromType) && isExactNumeric(toType))
- || (isInterval(toType) && isExactNumeric(fromType))) {
- IntervalSqlType intervalType =
- (IntervalSqlType) (isInterval(fromType) ? fromType : toType);
- if (!intervalType.getIntervalQualifier().isSingleDatetimeField()) {
- // Casts between intervals and exact numerics must involve
- // intervals with a single datetime field.
- return false;
- }
- }
- if (toTypeName == null || fromTypeName == null) {
- return false;
- }
-
- // REVIEW jvs 9-Feb-2009: we don't impose SQL rules for character sets
- // here; instead, we do that in SqlCastFunction. The reason is that
- // this method is called from at least one place (MedJdbcNameDirectory)
- // where internally a cast across character repertoires is OK. Should
- // probably clean that up.
-
- SqlTypeAssignmentRules rules = SqlTypeAssignmentRules.instance();
- return rules.canCastFrom(toTypeName, fromTypeName, coerce);
- }
-
- /**
- * Flattens a record type by recursively expanding any fields which are
- * themselves record types. For each record type, a representative null
- * value field is also prepended (with state NULL for a null value and FALSE
- * for non-null), and all component types are asserted to be nullable, since
- * SQL doesn't allow NOT NULL to be specified on attributes.
- *
- * @param typeFactory factory which should produced flattened type
- * @param recordType type with possible nesting
- * @param flatteningMap if non-null, receives map from unflattened ordinal
- * to flattened ordinal (must have length at least
- * recordType.getFieldList().size())
- * @return flattened equivalent
- */
- public static RelDataType flattenRecordType(
- RelDataTypeFactory typeFactory,
- RelDataType recordType,
- int[] flatteningMap) {
- if (!recordType.isStruct()) {
- return recordType;
- }
- List<RelDataTypeField> fieldList = new ArrayList<RelDataTypeField>();
- boolean nested =
- flattenFields(
- typeFactory,
- recordType,
- fieldList,
- flatteningMap);
- if (!nested) {
- return recordType;
- }
- List<RelDataType> types = new ArrayList<RelDataType>();
- List<String> fieldNames = new ArrayList<String>();
- int i = -1;
- for (RelDataTypeField field : fieldList) {
- ++i;
- types.add(field.getType());
- fieldNames.add(field.getName() + "_" + i);
- }
- return typeFactory.createStructType(types, fieldNames);
- }
-
- public static boolean needsNullIndicator(RelDataType recordType) {
- // NOTE jvs 9-Mar-2005: It would be more storage-efficient to say that
- // no null indicator is required for structured type columns declared
- // as NOT NULL. However, the uniformity of always having a null
- // indicator makes things cleaner in many places.
- return recordType.getSqlTypeName() == SqlTypeName.STRUCTURED;
- }
-
- private static boolean flattenFields(
- RelDataTypeFactory typeFactory,
- RelDataType type,
- List<RelDataTypeField> list,
- int[] flatteningMap) {
- boolean nested = false;
- if (needsNullIndicator(type)) {
- // NOTE jvs 9-Mar-2005: other code
- // (e.g. RelStructuredTypeFlattener) relies on the
- // null indicator field coming first.
- RelDataType indicatorType =
- typeFactory.createSqlType(SqlTypeName.BOOLEAN);
- if (type.isNullable()) {
- indicatorType =
- typeFactory.createTypeWithNullability(
- indicatorType,
- true);
- }
- RelDataTypeField nullIndicatorField =
- new RelDataTypeFieldImpl(
- "NULL_VALUE",
- 0,
- indicatorType);
- list.add(nullIndicatorField);
- nested = true;
- }
- for (RelDataTypeField field : type.getFieldList()) {
- if (flatteningMap != null) {
- flatteningMap[field.getIndex()] = list.size();
- }
- if (field.getType().isStruct()) {
- nested = true;
- flattenFields(
- typeFactory,
- field.getType(),
- list,
- null);
- } else if (field.getType().getComponentType() != null) {
- nested = true;
-
- // TODO jvs 14-Feb-2005: generalize to any kind of
- // collection type
- RelDataType flattenedCollectionType =
- typeFactory.createMultisetType(
- flattenRecordType(
- typeFactory,
- field.getType().getComponentType(),
- null),
- -1);
- field =
- new RelDataTypeFieldImpl(
- field.getName(),
- field.getIndex(),
- flattenedCollectionType);
- list.add(field);
- } else {
- list.add(field);
- }
- }
- return nested;
- }
-
- /**
- * Converts an instance of RelDataType to an instance of SqlDataTypeSpec.
- *
- * @param type type descriptor
- * @return corresponding parse representation
- */
- public static SqlDataTypeSpec convertTypeToSpec(RelDataType type) {
- SqlTypeName typeName = type.getSqlTypeName();
-
- // TODO jvs 28-Dec-2004: support row types, user-defined types,
- // interval types, multiset types, etc
- assert typeName != null;
- SqlIdentifier typeIdentifier =
- new SqlIdentifier(
- typeName.name(),
- SqlParserPos.ZERO);
-
- String charSetName = null;
-
- if (inCharFamily(type)) {
- charSetName = type.getCharset().name();
- // TODO jvs 28-Dec-2004: collation
- }
-
- // REVIEW jvs 28-Dec-2004: discriminate between precision/scale
- // zero and unspecified?
-
- // REVIEW angel 11-Jan-2006:
- // Use neg numbers to indicate unspecified precision/scale
-
- if (typeName.allowsScale()) {
- return new SqlDataTypeSpec(
- typeIdentifier,
- type.getPrecision(),
- type.getScale(),
- charSetName,
- null,
- SqlParserPos.ZERO);
- } else if (typeName.allowsPrec()) {
- return new SqlDataTypeSpec(
- typeIdentifier,
- type.getPrecision(),
- -1,
- charSetName,
- null,
- SqlParserPos.ZERO);
- } else {
- return new SqlDataTypeSpec(
- typeIdentifier,
- -1,
- -1,
- charSetName,
- null,
- SqlParserPos.ZERO);
- }
- }
-
- public static RelDataType createMultisetType(
- RelDataTypeFactory typeFactory,
- RelDataType type,
- boolean nullable) {
- RelDataType ret = typeFactory.createMultisetType(type, -1);
- return typeFactory.createTypeWithNullability(ret, nullable);
- }
-
- public static RelDataType createArrayType(
- RelDataTypeFactory typeFactory,
- RelDataType type,
- boolean nullable) {
- RelDataType ret = typeFactory.createArrayType(type, -1);
- return typeFactory.createTypeWithNullability(ret, nullable);
- }
-
- public static RelDataType createMapType(
- RelDataTypeFactory typeFactory,
- RelDataType keyType,
- RelDataType valueType,
- boolean nullable) {
- RelDataType ret = typeFactory.createMapType(keyType, valueType);
- return typeFactory.createTypeWithNullability(ret, nullable);
- }
-
- /**
- * Adds collation and charset to a character type, returns other types
- * unchanged.
- *
- * @param type Type
- * @param typeFactory Type factory
- * @return Type with added charset and collation, or unchanged type if it is
- * not a char type.
- */
- public static RelDataType addCharsetAndCollation(
- RelDataType type,
- RelDataTypeFactory typeFactory) {
- if (!inCharFamily(type)) {
- return type;
- }
- Charset charset = type.getCharset();
- if (charset == null) {
- charset = typeFactory.getDefaultCharset();
- }
- SqlCollation collation = type.getCollation();
- if (collation == null) {
- collation = SqlCollation.IMPLICIT;
- }
-
- // todo: should get the implicit collation from repository
- // instead of null
- type =
- typeFactory.createTypeWithCharsetAndCollation(
- type,
- charset,
- collation);
- SqlValidatorUtil.checkCharsetAndCollateConsistentIfCharType(type);
- return type;
- }
-
- /**
- * Returns whether two types are equal, ignoring nullability.
- *
- * <p>They need not come from the same factory.
- *
- * @param factory Type factory
- * @param type1 First type
- * @param type2 Second type
- * @return whether types are equal, ignoring nullability
- */
- public static boolean equalSansNullability(
- RelDataTypeFactory factory,
- RelDataType type1,
- RelDataType type2) {
- if (type1.equals(type2)) {
- return true;
- }
-
- if (isAny(type1) || isAny(type2)) {
- return true;
- }
-
- if (type1.isNullable() == type2.isNullable()) {
- // If types have the same nullability and they weren't equal above,
- // they must be different.
- return false;
- }
- return type1.equals(
- factory.createTypeWithNullability(type2, type1.isNullable()));
- }
-
- /**
- * Returns the ordinal of a given field in a record type, or -1 if the field
- * is not found.
- *
- * @param type Record type
- * @param fieldName Name of field
- * @return Ordinal of field
- */
- public static int findField(RelDataType type, String fieldName) {
- List<RelDataTypeField> fields = type.getFieldList();
- for (int i = 0; i < fields.size(); i++) {
- RelDataTypeField field = fields.get(i);
- if (field.getName().equals(fieldName)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Selects data types of the specified fields from an input row type.
- * This is useful when identifying data types of a function that is going
- * to operate on inputs that are specified as field ordinals (e.g.
- * aggregate calls).
- *
- * @param rowType input row type
- * @param requiredFields ordinals of the projected fields
- * @return list of data types that are requested by requiredFields
- */
- public static List<RelDataType> projectTypes(final RelDataType rowType,
- final List<? extends Number> requiredFields) {
- final List<RelDataTypeField> fields = rowType.getFieldList();
-
- return new AbstractList<RelDataType>() {
- @Override public RelDataType get(int index) {
- return fields.get(requiredFields.get(index).intValue()).getType();
- }
-
- @Override public int size() {
- return requiredFields.size();
- }
- };
- }
-
- /**
- * Records a struct type with no fields.
- *
- * @param typeFactory Type factory
- * @return Struct type with no fields
- */
- public static RelDataType createEmptyStructType(
- RelDataTypeFactory typeFactory) {
- return typeFactory.createStructType(
- ImmutableList.<RelDataType>of(),
- ImmutableList.<String>of());
- }
-
- /** Returns whether a type is flat. It is not flat if it is a record type that
- * has one or more fields that are themselves record types. */
- public static boolean isFlat(RelDataType type) {
- if (type.isStruct()) {
- for (RelDataTypeField field : type.getFieldList()) {
- if (field.getType().isStruct()) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Returns whether two types are comparable. They need to be scalar types of
- * the same family, or struct types whose fields are pairwise comparable.
- *
- * @param type1 First type
- * @param type2 Second type
- * @return Whether types are comparable
- */
- public static boolean isComparable(RelDataType type1, RelDataType type2) {
- if (type1.isStruct() != type2.isStruct()) {
- return false;
- }
-
- if (type1.isStruct()) {
- int n = type1.getFieldCount();
- if (n != type2.getFieldCount()) {
- return false;
- }
- for (Pair<RelDataTypeField, RelDataTypeField> pair
- : Pair.zip(type1.getFieldList(), type2.getFieldList())) {
- if (!isComparable(pair.left.getType(), pair.right.getType())) {
- return false;
- }
- }
- return true;
- }
- RelDataTypeFamily family1 = null;
- RelDataTypeFamily family2 = null;
-
- // REVIEW jvs 2-June-2005: This is needed to keep
- // the Saffron type system happy.
- if (type1.getSqlTypeName() != null) {
- family1 = type1.getSqlTypeName().getFamily();
- }
- if (type2.getSqlTypeName() != null) {
- family2 = type2.getSqlTypeName().getFamily();
- }
- if (family1 == null) {
- family1 = type1.getFamily();
- }
- if (family2 == null) {
- family2 = type2.getFamily();
- }
- if (family1 == family2) {
- return true;
- }
-
- // If one of the operators is of type 'ANY', return true.
- if (family1 == SqlTypeFamily.ANY
- || family2 == SqlTypeFamily.ANY) {
- return true;
- }
-
- // We can implicitly convert from character to date
- if (family1 == SqlTypeFamily.CHARACTER
- && canConvertStringInCompare(family2)
- || family2 == SqlTypeFamily.CHARACTER
- && canConvertStringInCompare(family1)) {
- return true;
- }
-
- // HACK POINT: allow boolean = integer (integer = boolean)
- if (type1 instanceof BasicSqlType && type2 instanceof BasicSqlType) {
- SqlTypeName typeName1 = ((BasicSqlType) type1).typeName;
- SqlTypeName typeName2 = ((BasicSqlType) type2).typeName;
- if (typeName1 == SqlTypeName.INTEGER
- && typeName2 == SqlTypeName.BOOLEAN
- || typeName1 == SqlTypeName.BOOLEAN
- && typeName2 == SqlTypeName.INTEGER) {
- return true;
- }
- }
-
- return false;
- }
-
- /** Returns whether a character data type can be implicitly converted to a
- * given family in a compare operation. */
- private static boolean canConvertStringInCompare(RelDataTypeFamily family) {
- if (family instanceof SqlTypeFamily) {
- SqlTypeFamily sqlTypeFamily = (SqlTypeFamily) family;
- switch (sqlTypeFamily) {
- case DATE:
- case TIME:
- case TIMESTAMP:
- case INTERVAL_DAY_TIME:
- case INTERVAL_YEAR_MONTH:
- case NUMERIC:
- case APPROXIMATE_NUMERIC:
- case EXACT_NUMERIC:
- case INTEGER:
- case BOOLEAN:
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks whether a type represents Unicode character data.
- *
- * @param type type to test
- * @return whether type represents Unicode character data
- */
- public static boolean isUnicode(RelDataType type) {
- Charset charset = type.getCharset();
- if (charset == null) {
- return false;
- }
- return charset.name().startsWith("UTF");
- }
-
- /** Returns the larger of two precisions, treating
- * {@link RelDataType#PRECISION_NOT_SPECIFIED} as infinity. */
- public static int maxPrecision(int p0, int p1) {
- return (p0 == RelDataType.PRECISION_NOT_SPECIFIED
- || p0 >= p1
- && p1 != RelDataType.PRECISION_NOT_SPECIFIED) ? p0 : p1;
- }
-
- /** Returns whether a precision is greater or equal than another,
- * treating {@link RelDataType#PRECISION_NOT_SPECIFIED} as infinity. */
- public static int comparePrecision(int p0, int p1) {
- if (p0 == p1) {
- return 0;
- }
- if (p0 == RelDataType.PRECISION_NOT_SPECIFIED) {
- return 1;
- }
- if (p1 == RelDataType.PRECISION_NOT_SPECIFIED) {
- return -1;
- }
- return Integer.compare(p0, p1);
- }
-
- public static boolean isArray(RelDataType type) {
- return type.getSqlTypeName() == SqlTypeName.ARRAY;
- }
-}
-
-// End SqlTypeUtil.java
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
deleted file mode 100644
index 70d1b2a..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.calcite.sql2rel;
-
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.util.ReflectiveVisitor;
-
-/*
- * OVERRIDE POINT:
- * - disable the whole RelFieldTrimmer
- */
-
-public class RelFieldTrimmer implements ReflectiveVisitor {
-
- public RelFieldTrimmer(SqlValidator validator, RelBuilder relBuilder) {
- }
-
- public RelFieldTrimmer(SqlValidator validator, RelOptCluster cluster, RelFactories.ProjectFactory projectFactory, RelFactories.FilterFactory filterFactory, RelFactories.JoinFactory joinFactory, RelFactories.SemiJoinFactory semiJoinFactory, RelFactories.SortFactory sortFactory, RelFactories.AggregateFactory aggregateFactory, RelFactories.SetOpFactory setOpFactory) {
- }
-
- public RelNode trim(RelNode rootRel) {
- return rootRel;
- }
-
-}
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
deleted file mode 100644
index 519a73b..0000000
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ /dev/null
@@ -1,5656 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-package org.apache.calcite.sql2rel;
-
-import static org.apache.calcite.sql.SqlUtil.stripAs;
-import static org.apache.calcite.util.Static.RESOURCE;
-
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.util.AbstractList;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.calcite.avatica.util.Spaces;
-import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.plan.Convention;
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelOptSamplingParameters;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.prepare.Prepare;
-import org.apache.calcite.prepare.RelOptTableImpl;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollationImpl;
-import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelFieldCollation;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.RelRoot;
-import org.apache.calcite.rel.SingleRel;
-import org.apache.calcite.rel.core.Aggregate;
-import org.apache.calcite.rel.core.AggregateCall;
-import org.apache.calcite.rel.core.Collect;
-import org.apache.calcite.rel.core.CorrelationId;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.calcite.rel.core.Join;
-import org.apache.calcite.rel.core.JoinInfo;
-import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.calcite.rel.core.Project;
-import org.apache.calcite.rel.core.RelFactories;
-import org.apache.calcite.rel.core.Sample;
-import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.core.Uncollect;
-import org.apache.calcite.rel.logical.LogicalAggregate;
-import org.apache.calcite.rel.logical.LogicalCorrelate;
-import org.apache.calcite.rel.logical.LogicalFilter;
-import org.apache.calcite.rel.logical.LogicalIntersect;
-import org.apache.calcite.rel.logical.LogicalJoin;
-import org.apache.calcite.rel.logical.LogicalMatch;
-import org.apache.calcite.rel.logical.LogicalMinus;
-import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rel.logical.LogicalSort;
-import org.apache.calcite.rel.logical.LogicalTableFunctionScan;
-import org.apache.calcite.rel.logical.LogicalTableModify;
-import org.apache.calcite.rel.logical.LogicalTableScan;
-import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.rel.logical.LogicalValues;
-import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider;
-import org.apache.calcite.rel.metadata.RelColumnMapping;
-import org.apache.calcite.rel.metadata.RelMetadataQuery;
-import org.apache.calcite.rel.stream.Delta;
-import org.apache.calcite.rel.stream.LogicalDelta;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexCall;
-import org.apache.calcite.rex.RexCallBinding;
-import org.apache.calcite.rex.RexCorrelVariable;
-import org.apache.calcite.rex.RexDynamicParam;
-import org.apache.calcite.rex.RexFieldAccess;
-import org.apache.calcite.rex.RexFieldCollation;
-import org.apache.calcite.rex.RexInputRef;
-import org.apache.calcite.rex.RexLiteral;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexPatternFieldRef;
-import org.apache.calcite.rex.RexRangeRef;
-import org.apache.calcite.rex.RexShuttle;
-import org.apache.calcite.rex.RexSubQuery;
-import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.rex.RexWindowBound;
-import org.apache.calcite.schema.ModifiableTable;
-import org.apache.calcite.schema.ModifiableView;
-import org.apache.calcite.schema.Table;
-import org.apache.calcite.schema.TranslatableTable;
-import org.apache.calcite.schema.Wrapper;
-import org.apache.calcite.sql.JoinConditionType;
-import org.apache.calcite.sql.JoinType;
-import org.apache.calcite.sql.SemiJoinType;
-import org.apache.calcite.sql.SqlAggFunction;
-import org.apache.calcite.sql.SqlBasicCall;
-import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlCallBinding;
-import org.apache.calcite.sql.SqlDataTypeSpec;
-import org.apache.calcite.sql.SqlDelete;
-import org.apache.calcite.sql.SqlDynamicParam;
-import org.apache.calcite.sql.SqlExplainFormat;
-import org.apache.calcite.sql.SqlExplainLevel;
-import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.SqlIdentifier;
-import org.apache.calcite.sql.SqlInsert;
-import org.apache.calcite.sql.SqlIntervalQualifier;
-import org.apache.calcite.sql.SqlJoin;
-import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
-import org.apache.calcite.sql.SqlMatchRecognize;
-import org.apache.calcite.sql.SqlMerge;
-import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlNodeList;
-import org.apache.calcite.sql.SqlNumericLiteral;
-import org.apache.calcite.sql.SqlOperator;
-import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.SqlOrderBy;
-import org.apache.calcite.sql.SqlSampleSpec;
-import org.apache.calcite.sql.SqlSelect;
-import org.apache.calcite.sql.SqlSelectKeyword;
-import org.apache.calcite.sql.SqlSetOperator;
-import org.apache.calcite.sql.SqlUnnestOperator;
-import org.apache.calcite.sql.SqlUpdate;
-import org.apache.calcite.sql.SqlUtil;
-import org.apache.calcite.sql.SqlValuesOperator;
-import org.apache.calcite.sql.SqlWindow;
-import org.apache.calcite.sql.SqlWith;
-import org.apache.calcite.sql.SqlWithItem;
-import org.apache.calcite.sql.fun.SqlCountAggFunction;
-import org.apache.calcite.sql.fun.SqlInOperator;
-import org.apache.calcite.sql.fun.SqlRowOperator;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.SqlReturnTypeInference;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.sql.type.SqlTypeUtil;
-import org.apache.calcite.sql.type.TableFunctionReturnTypeInference;
-import org.apache.calcite.sql.util.SqlBasicVisitor;
-import org.apache.calcite.sql.util.SqlVisitor;
-import org.apache.calcite.sql.validate.AggregatingSelectScope;
-import org.apache.calcite.sql.validate.CollectNamespace;
-import org.apache.calcite.sql.validate.DelegatingScope;
-import org.apache.calcite.sql.validate.ListScope;
-import org.apache.calcite.sql.validate.MatchRecognizeScope;
-import org.apache.calcite.sql.validate.ParameterScope;
-import org.apache.calcite.sql.validate.SelectScope;
-import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlNameMatcher;
-import org.apache.calcite.sql.validate.SqlQualified;
-import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction;
-import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorImpl;
-import org.apache.calcite.sql.validate.SqlValidatorNamespace;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
-import org.apache.calcite.sql.validate.SqlValidatorTable;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.Litmus;
-import org.apache.calcite.util.NlsString;
-import org.apache.calcite.util.NumberUtil;
-import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Util;
-import org.apache.calcite.util.trace.CalciteTrace;
-import org.slf4j.Logger;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-/*
- * The code has synced with calcite. Hope one day, we could remove the hardcode override point.
- * OVERRIDE POINT:
- * - DEFAULT_IN_SUB_QUERY_THRESHOLD, was `20`, now `Integer.MAX_VALUE`
- * - isTrimUnusedFields(), override to false
- * - AggConverter.translateAgg(...), skip column reading for COUNT(COL), for https://jirap.corp.ebay.com/browse/KYLIN-104
- * - convertQuery(), call hackSelectStar() at the end
- * - createJoin() check cast operation
- */
-
-/**
- * Converts a SQL parse tree (consisting of
- * {@link org.apache.calcite.sql.SqlNode} objects) into a relational algebra
- * expression (consisting of {@link org.apache.calcite.rel.RelNode} objects).
- *
- * <p>The public entry points are: {@link #convertQuery},
- * {@link #convertExpression(SqlNode)}.
- */
-public class SqlToRelConverter {
- //~ Static fields/initializers ---------------------------------------------
-
- protected static final Logger SQL2REL_LOGGER =
- CalciteTrace.getSqlToRelTracer();
-
- private static final BigDecimal TWO = BigDecimal.valueOf(2L);
-
- /** Size of the smallest IN list that will be converted to a semijoin to a
- * static table. */
- /* OVERRIDE POINT */
- public static final int DEFAULT_IN_SUB_QUERY_THRESHOLD = Integer.MAX_VALUE;
-
- @Deprecated // to be removed before 2.0
- public static final int DEFAULT_IN_SUBQUERY_THRESHOLD =
- DEFAULT_IN_SUB_QUERY_THRESHOLD;
-
- //~ Instance fields --------------------------------------------------------
-
- protected final SqlValidator validator;
- protected final RexBuilder rexBuilder;
- protected final Prepare.CatalogReader catalogReader;
- protected final RelOptCluster cluster;
- private SubQueryConverter subQueryConverter;
- protected final List<RelNode> leaves = new ArrayList<>();
- private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
- private final SqlOperatorTable opTab;
- protected final RelDataTypeFactory typeFactory;
- private final SqlNodeToRexConverter exprConverter;
- private int explainParamCount;
- public final SqlToRelConverter.Config config;
-
- /**
- * Fields used in name resolution for correlated sub-queries.
- */
- private final Map<CorrelationId, DeferredLookup> mapCorrelToDeferred =
- new HashMap<>();
-
- /**
- * Stack of names of datasets requested by the <code>
- * TABLE(SAMPLE(<datasetName>, <query>))</code> construct.
- */
- private final Deque<String> datasetStack = new ArrayDeque<>();
-
- /**
- * Mapping of non-correlated sub-queries that have been converted to their
- * equivalent constants. Used to avoid re-evaluating the sub-query if it's
- * already been evaluated.
- */
- private final Map<SqlNode, RexNode> mapConvertedNonCorrSubqs =
- new HashMap<>();
-
- public final RelOptTable.ViewExpander viewExpander;
-
- //~ Constructors -----------------------------------------------------------
- /**
- * Creates a converter.
- *
- * @param viewExpander Preparing statement
- * @param validator Validator
- * @param catalogReader Schema
- * @param planner Planner
- * @param rexBuilder Rex builder
- * @param convertletTable Expression converter
- */
- @Deprecated // to be removed before 2.0
- public SqlToRelConverter(
- RelOptTable.ViewExpander viewExpander,
- SqlValidator validator,
- Prepare.CatalogReader catalogReader,
- RelOptPlanner planner,
- RexBuilder rexBuilder,
- SqlRexConvertletTable convertletTable) {
- this(viewExpander, validator, catalogReader,
- RelOptCluster.create(planner, rexBuilder), convertletTable,
- Config.DEFAULT);
- }
-
- @Deprecated // to be removed before 2.0
- public SqlToRelConverter(
- RelOptTable.ViewExpander viewExpander,
- SqlValidator validator,
- Prepare.CatalogReader catalogReader,
- RelOptCluster cluster,
- SqlRexConvertletTable convertletTable) {
- this(viewExpander, validator, catalogReader, cluster, convertletTable,
- Config.DEFAULT);
- }
-
- /* Creates a converter. */
- public SqlToRelConverter(
- RelOptTable.ViewExpander viewExpander,
- SqlValidator validator,
- Prepare.CatalogReader catalogReader,
- RelOptCluster cluster,
- SqlRexConvertletTable convertletTable,
- Config config) {
- this.viewExpander = viewExpander;
- this.opTab =
- (validator
- == null) ? SqlStdOperatorTable.instance()
- : validator.getOperatorTable();
- this.validator = validator;
- this.catalogReader = catalogReader;
- this.subQueryConverter = new NoOpSubQueryConverter();
- this.rexBuilder = cluster.getRexBuilder();
- this.typeFactory = rexBuilder.getTypeFactory();
- this.cluster = Preconditions.checkNotNull(cluster);
- this.exprConverter = new SqlNodeToRexConverterImpl(convertletTable);
- this.explainParamCount = 0;
- this.config = new ConfigBuilder().withConfig(config).build();
- }
-
- //~ Methods ----------------------------------------------------------------
-
- /**
- * @return the RelOptCluster in use.
- */
- public RelOptCluster getCluster() {
- return cluster;
- }
-
- /**
- * Returns the row-expression builder.
- */
- public RexBuilder getRexBuilder() {
- return rexBuilder;
- }
-
- /**
- * Returns the number of dynamic parameters encountered during translation;
- * this must only be called after {@link #convertQuery}.
- *
- * @return number of dynamic parameters
- */
- public int getDynamicParamCount() {
- return dynamicParamSqlNodes.size();
- }
-
- /**
- * Returns the type inferred for a dynamic parameter.
- *
- * @param index 0-based index of dynamic parameter
- * @return inferred type, never null
- */
- public RelDataType getDynamicParamType(int index) {
- SqlNode sqlNode = dynamicParamSqlNodes.get(index);
- if (sqlNode == null) {
- throw Util.needToImplement("dynamic param type inference");
- }
- return validator.getValidatedNodeType(sqlNode);
- }
-
- /**
- * Returns the current count of the number of dynamic parameters in an
- * EXPLAIN PLAN statement.
- *
- * @param increment if true, increment the count
- * @return the current count before the optional increment
- */
- public int getDynamicParamCountInExplain(boolean increment) {
- int retVal = explainParamCount;
- if (increment) {
- ++explainParamCount;
- }
- return retVal;
- }
-
- /**
- * @return mapping of non-correlated sub-queries that have been converted to
- * the constants that they evaluate to
- */
- public Map<SqlNode, RexNode> getMapConvertedNonCorrSubqs() {
- return mapConvertedNonCorrSubqs;
- }
-
- /**
- * Adds to the current map of non-correlated converted sub-queries the
- * elements from another map that contains non-correlated sub-queries that
- * have been converted by another SqlToRelConverter.
- *
- * @param alreadyConvertedNonCorrSubqs the other map
- */
- public void addConvertedNonCorrSubqs(
- Map<SqlNode, RexNode> alreadyConvertedNonCorrSubqs) {
- mapConvertedNonCorrSubqs.putAll(alreadyConvertedNonCorrSubqs);
- }
-
- /**
- * Sets a new SubQueryConverter. To have any effect, this must be called
- * before any convert method.
- *
- * @param converter new SubQueryConverter
- */
- public void setSubQueryConverter(SubQueryConverter converter) {
- subQueryConverter = converter;
- }
-
- /**
- * Sets the number of dynamic parameters in the current EXPLAIN PLAN
- * statement.
- *
- * @param explainParamCount number of dynamic parameters in the statement
- */
- public void setDynamicParamCountInExplain(int explainParamCount) {
- assert config.isExplain();
- this.explainParamCount = explainParamCount;
- }
-
- private void checkConvertedType(SqlNode query, RelNode result) {
- if (query.isA(SqlKind.DML)) {
- return;
- }
- // Verify that conversion from SQL to relational algebra did
- // not perturb any type information. (We can't do this if the
- // SQL statement is something like an INSERT which has no
- // validator type information associated with its result,
- // hence the namespace check above.)
- final List<RelDataTypeField> validatedFields =
- validator.getValidatedNodeType(query).getFieldList();
- final RelDataType validatedRowType =
- validator.getTypeFactory().createStructType(
- Pair.right(validatedFields),
- SqlValidatorUtil.uniquify(Pair.left(validatedFields),
- catalogReader.nameMatcher().isCaseSensitive()));
-
- final List<RelDataTypeField> convertedFields =
- result.getRowType().getFieldList().subList(0, validatedFields.size());
- final RelDataType convertedRowType =
- validator.getTypeFactory().createStructType(convertedFields);
-
- if (!RelOptUtil.equal("validated row type", validatedRowType,
- "converted row type", convertedRowType, Litmus.IGNORE)) {
- throw new AssertionError("Conversion to relational algebra failed to "
- + "preserve datatypes:\n"
- + "validated type:\n"
- + validatedRowType.getFullTypeString()
- + "\nconverted type:\n"
- + convertedRowType.getFullTypeString()
- + "\nrel:\n"
- + RelOptUtil.toString(result));
- }
- }
-
- public RelNode flattenTypes(
- RelNode rootRel,
- boolean restructure) {
- RelStructuredTypeFlattener typeFlattener =
- new RelStructuredTypeFlattener(rexBuilder, createToRelContext(), restructure);
- return typeFlattener.rewrite(rootRel);
- }
-
- /**
- * If sub-query is correlated and decorrelation is enabled, performs
- * decorrelation.
- *
- * @param query Query
- * @param rootRel Root relational expression
- * @return New root relational expression after decorrelation
- */
- public RelNode decorrelate(SqlNode query, RelNode rootRel) {
- if (!enableDecorrelation()) {
- return rootRel;
- }
- final RelNode result = decorrelateQuery(rootRel);
- if (result != rootRel) {
- checkConvertedType(query, result);
- }
- return result;
- }
-
- /**
- * Walks over a tree of relational expressions, replacing each
- * {@link RelNode} with a 'slimmed down' relational expression that projects
- * only the fields required by its consumer.
- *
- * <p>This may make things easier for the optimizer, by removing crud that
- * would expand the search space, but is difficult for the optimizer itself
- * to do it, because optimizer rules must preserve the number and type of
- * fields. Hence, this transform that operates on the entire tree, similar
- * to the {@link RelStructuredTypeFlattener type-flattening transform}.
- *
- * <p>Currently this functionality is disabled in farrago/luciddb; the
- * default implementation of this method does nothing.
- *
- * @param ordered Whether the relational expression must produce results in
- * a particular order (typically because it has an ORDER BY at top level)
- * @param rootRel Relational expression that is at the root of the tree
- * @return Trimmed relational expression
- */
- public RelNode trimUnusedFields(boolean ordered, RelNode rootRel) {
- // Trim fields that are not used by their consumer.
- if (isTrimUnusedFields()) {
- final RelFieldTrimmer trimmer = newFieldTrimmer();
- final List<RelCollation> collations =
- rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
- rootRel = trimmer.trim(rootRel);
- if (!ordered
- && collations != null
- && !collations.isEmpty()
- && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
- final RelTraitSet traitSet = rootRel.getTraitSet()
- .replace(RelCollationTraitDef.INSTANCE, collations);
- rootRel = rootRel.copy(traitSet, rootRel.getInputs());
- }
- if (SQL2REL_LOGGER.isDebugEnabled()) {
- SQL2REL_LOGGER.debug(
- RelOptUtil.dumpPlan("Plan after trimming unused fields", rootRel,
- SqlExplainFormat.TEXT, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
- }
- }
- return rootRel;
- }
-
- /**
- * Creates a RelFieldTrimmer.
- *
- * @return Field trimmer
- */
- protected RelFieldTrimmer newFieldTrimmer() {
- final RelBuilder relBuilder =
- RelFactories.LOGICAL_BUILDER.create(cluster, null);
- return new RelFieldTrimmer(validator, relBuilder);
- }
-
- /**
- * Converts an unvalidated query's parse tree into a relational expression.
- *
- * @param query Query to convert
- * @param needsValidation Whether to validate the query before converting;
- * <code>false</code> if the query has already been
- * validated.
- * @param top Whether the query is top-level, say if its result
- * will become a JDBC result set; <code>false</code> if
- * the query will be part of a view.
- */
- public RelRoot convertQuery(
- SqlNode query,
- final boolean needsValidation,
- final boolean top) {
-
- SqlNode origQuery = query; /* OVERRIDE POINT */
-
- if (needsValidation) {
- query = validator.validate(query);
- }
-
- RelMetadataQuery.THREAD_PROVIDERS.set(
- JaninoRelMetadataProvider.of(cluster.getMetadataProvider()));
- RelNode result = convertQueryRecursive(query, top, null).rel;
- if (top) {
- if (isStream(query)) {
- result = new LogicalDelta(cluster, result.getTraitSet(), result);
- }
- }
- RelCollation collation = RelCollations.EMPTY;
- if (!query.isA(SqlKind.DML)) {
- if (isOrdered(query)) {
- collation = requiredCollation(result);
- }
- }
- checkConvertedType(query, result);
-
- if (SQL2REL_LOGGER.isDebugEnabled()) {
- SQL2REL_LOGGER.debug(
- RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode",
- result, SqlExplainFormat.TEXT,
- SqlExplainLevel.EXPPLAN_ATTRIBUTES));
- }
-
- final RelDataType validatedRowType = validator.getValidatedNodeType(query);
- RelRoot origResult = RelRoot.of(result, validatedRowType, query.getKind())
- .withCollation(collation);
- return hackSelectStar(origQuery, origResult);
- }
-
- /* OVERRIDE POINT */
- private RelRoot hackSelectStar(SqlNode query, RelRoot root) {
- // /*
- // * Rel tree is like:
- // *
- // * LogicalSort (optional)
- // * |- LogicalProject
- // * |- LogicalFilter (optional)
- // * |- OLAPTableScan or LogicalJoin
- // */
- LogicalProject rootPrj = null;
- LogicalSort rootSort = null;
- if (root.rel instanceof LogicalProject) {
- rootPrj = (LogicalProject) root.rel;
- } else if (root.rel instanceof LogicalSort && root.rel.getInput(0) instanceof LogicalProject) {
- rootPrj = (LogicalProject) root.rel.getInput(0);
- rootSort = (LogicalSort) root.rel;
- } else {
- return root;
- }
-
- //
- RelNode input = rootPrj.getInput();
- // if (!(//
- // isAmong(input, "OLAPTableScan", "LogicalJoin")//
- // || (isAmong(input, "LogicalFilter") && isAmong(input.getInput(0), "OLAPTableScan", "LogicalJoin"))//
- // ))
- // return root;
- //
- // if (rootPrj.getRowType().getFieldCount() < input.getRowType().getFieldCount())
- // return root;
-
- RelDataType inType = rootPrj.getRowType();
- List<String> inFields = inType.getFieldNames();
- List<RexNode> projExp = new ArrayList<>();
- List<Pair<Integer, String>> projFields = new ArrayList<>();
- Map<Integer,Integer> projFieldMapping = new HashMap<>();
- RelDataTypeFactory.FieldInfoBuilder projTypeBuilder = getCluster().getTypeFactory().builder();
- RelDataTypeFactory.FieldInfoBuilder validTypeBuilder = getCluster().getTypeFactory().builder();
-
- boolean hiddenColumnExists = false;
- for (int i = 0; i < root.validatedRowType.getFieldList().size(); i++) {
- if (root.validatedRowType.getFieldNames().get(i).startsWith("_KY_"))
- hiddenColumnExists = true;
- }
- if(!hiddenColumnExists) {
- return root;
- }
-
- for (int i = 0; i < inFields.size(); i++) {
- if (!inFields.get(i).startsWith("_KY_")) {
- projExp.add(rootPrj.getProjects().get(i));
- projFieldMapping.put(i, projFields.size());
- projFields.add(Pair.of(projFields.size(), inFields.get(i)));
- projTypeBuilder.add(inType.getFieldList().get(i));
-
- if (i < root.validatedRowType.getFieldList().size()) //for cases like kylin-it/src/test/resources/query/sql_verifyCount/query10.sql
- validTypeBuilder.add(root.validatedRowType.getFieldList().get(i));
- }
- }
-
- RelDataType projRowType = getCluster().getTypeFactory().createStructType(projTypeBuilder);
- rootPrj = LogicalProject.create(input, projExp, projRowType);
- if (rootSort != null) {
- //for cases like kylin-it/src/test/resources/query/sql_verifyCount/query10.sql, original RelCollation is stale, need to fix its fieldIndex
- RelCollation originalCollation = rootSort.collation;
- RelCollation newCollation = null;
- List<RelFieldCollation> fieldCollations = originalCollation.getFieldCollations();
- ImmutableList.Builder<RelFieldCollation> newFieldCollations = ImmutableList.builder();
- for (RelFieldCollation fieldCollation : fieldCollations) {
- if(projFieldMapping.containsKey(fieldCollation.getFieldIndex())) {
- newFieldCollations.add(fieldCollation.copy(projFieldMapping.get(fieldCollation.getFieldIndex())));
- } else {
- newFieldCollations.add(fieldCollation);
- }
- }
- newCollation = RelCollationImpl.of(newFieldCollations.build());
- rootSort = LogicalSort.create(rootPrj, newCollation, rootSort.offset, rootSort.fetch);
- }
-
- RelDataType validRowType = getCluster().getTypeFactory().createStructType(validTypeBuilder);
- root = new RelRoot(rootSort == null ? rootPrj : rootSort, validRowType, root.kind, projFields, rootSort == null ? root.collation : rootSort.getCollation());
-
- validator.setValidatedNodeType(query, validRowType);
-
- return root;
- }
-
- private static boolean isStream(SqlNode query) {
- return query instanceof SqlSelect
- && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
- }
-
- public static boolean isOrdered(SqlNode query) {
- switch (query.getKind()) {
- case SELECT:
- return ((SqlSelect) query).getOrderList() != null
- && ((SqlSelect) query).getOrderList().size() > 0;
- case WITH:
- return isOrdered(((SqlWith) query).body);
- case ORDER_BY:
- return ((SqlOrderBy) query).orderList.size() > 0;
- default:
- return false;
- }
- }
-
- private RelCollation requiredCollation(RelNode r) {
- if (r instanceof Sort) {
- return ((Sort) r).collation;
- }
- if (r instanceof Project) {
- return requiredCollation(((Project) r).getInput());
- }
- if (r instanceof Delta) {
- return requiredCollation(((Delta) r).getInput());
- }
- throw new AssertionError();
- }
-
- /**
- * Converts a SELECT statement's parse tree into a relational expression.
- */
- public RelNode convertSelect(SqlSelect select, boolean top) {
- final SqlValidatorScope selectScope = validator.getWhereScope(select);
- final Blackboard bb = createBlackboard(selectScope, null, top);
- convertSelectImpl(bb, select);
- return bb.root;
- }
-
- /**
- * Factory method for creating translation workspace.
- */
- protected Blackboard createBlackboard(SqlValidatorScope scope,
- Map<String, RexNode> nameToNodeMap, boolean top) {
- return new Blackboard(scope, nameToNodeMap, top);
- }
-
- /**
- * Implementation of {@link #convertSelect(SqlSelect, boolean)};
- * derived class may override.
- */
- protected void convertSelectImpl(
- final Blackboard bb,
- SqlSelect select) {
- convertFrom(
- bb,
- select.getFrom());
- convertWhere(
- bb,
- select.getWhere());
-
- final List<SqlNode> orderExprList = new ArrayList<>();
- final List<RelFieldCollation> collationList = new ArrayList<>();
- gatherOrderExprs(
- bb,
- select,
- select.getOrderList(),
- orderExprList,
- collationList);
- final RelCollation collation =
- cluster.traitSet().canonize(RelCollations.of(collationList));
-
- if (validator.isAggregate(select)) {
- convertAgg(
- bb,
- select,
- orderExprList);
- } else {
- convertSelectList(
- bb,
- select,
- orderExprList);
- }
-
- if (select.isDistinct()) {
- distinctify(bb, true);
- }
- convertOrder(
- select, bb, collation, orderExprList, select.getOffset(),
- select.getFetch());
- bb.setRoot(bb.root, true);
- }
-
- /**
- * Having translated 'SELECT ... FROM ... [GROUP BY ...] [HAVING ...]', adds
- * a relational expression to make the results unique.
- *
- * <p>If the SELECT clause contains duplicate expressions, adds
- * {@link org.apache.calcite.rel.logical.LogicalProject}s so that we are
- * grouping on the minimal set of keys. The performance gain isn't huge, but
- * it is difficult to detect these duplicate expressions later.
- *
- * @param bb Blackboard
- * @param checkForDupExprs Check for duplicate expressions
- */
- private void distinctify(
- Blackboard bb,
- boolean checkForDupExprs) {
- // Look for duplicate expressions in the project.
- // Say we have 'select x, y, x, z'.
- // Then dups will be {[2, 0]}
- // and oldToNew will be {[0, 0], [1, 1], [2, 0], [3, 2]}
- RelNode rel = bb.root;
- if (checkForDupExprs && (rel instanceof LogicalProject)) {
- LogicalProject project = (LogicalProject) rel;
- final List<RexNode> projectExprs = project.getProjects();
- final List<Integer> origins = new ArrayList<>();
- int dupCount = 0;
- for (int i = 0; i < projectExprs.size(); i++) {
- int x = findExpr(projectExprs.get(i), projectExprs, i);
- if (x >= 0) {
- origins.add(x);
- ++dupCount;
- } else {
- origins.add(i);
- }
- }
- if (dupCount == 0) {
- distinctify(bb, false);
- return;
- }
-
- final Map<Integer, Integer> squished = Maps.newHashMap();
- final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
- final List<Pair<RexNode, String>> newProjects = Lists.newArrayList();
- for (int i = 0; i < fields.size(); i++) {
- if (origins.get(i) == i) {
- squished.put(i, newProjects.size());
- newProjects.add(RexInputRef.of2(i, fields));
- }
- }
- rel =
- LogicalProject.create(rel, Pair.left(newProjects),
- Pair.right(newProjects));
- bb.root = rel;
- distinctify(bb, false);
- rel = bb.root;
-
- // Create the expressions to reverse the mapping.
- // Project($0, $1, $0, $2).
- final List<Pair<RexNode, String>> undoProjects = Lists.newArrayList();
- for (int i = 0; i < fields.size(); i++) {
- final int origin = origins.get(i);
- RelDataTypeField field = fields.get(i);
- undoProjects.add(
- Pair.of(
- (RexNode) new RexInputRef(
- squished.get(origin), field.getType()),
- field.getName()));
- }
-
- rel =
- LogicalProject.create(rel, Pair.left(undoProjects),
- Pair.right(undoProjects));
- bb.setRoot(
- rel,
- false);
-
- return;
- }
-
- // Usual case: all of the expressions in the SELECT clause are
- // different.
- final ImmutableBitSet groupSet =
- ImmutableBitSet.range(rel.getRowType().getFieldCount());
- rel =
- createAggregate(bb, false, groupSet, ImmutableList.of(groupSet),
- ImmutableList.<AggregateCall>of());
-
- bb.setRoot(
- rel,
- false);
- }
-
- private int findExpr(RexNode seek, List<RexNode> exprs, int count) {
- for (int i = 0; i < count; i++) {
- RexNode expr = exprs.get(i);
- if (expr.toString().equals(seek.toString())) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Converts a query's ORDER BY clause, if any.
- *
- * @param select Query
- * @param bb Blackboard
- * @param collation Collation list
- * @param orderExprList Method populates this list with orderBy expressions
- * not present in selectList
- * @param offset Expression for number of rows to discard before
- * returning first row
- * @param fetch Expression for number of rows to fetch
- */
- protected void convertOrder(
- SqlSelect select,
- Blackboard bb,
- RelCollation collation,
- List<SqlNode> orderExprList,
- SqlNode offset,
- SqlNode fetch) {
- if (select.getOrderList() == null
- || select.getOrderList().getList().isEmpty()) {
- assert collation.getFieldCollations().isEmpty();
- if ((offset == null
- || ((SqlLiteral) offset).bigDecimalValue().equals(BigDecimal.ZERO))
- && fetch == null) {
- return;
- }
- }
-
- // Create a sorter using the previously constructed collations.
- bb.setRoot(
- LogicalSort.create(bb.root, collation,
- offset == null ? null : convertExpression(offset),
- fetch == null ? null : convertExpression(fetch)),
- false);
-
- // If extra expressions were added to the project list for sorting,
- // add another project to remove them. But make the collation empty, because
- // we can't represent the real collation.
- //
- // If it is the top node, use the real collation, but don't trim fields.
- if (orderExprList.size() > 0 && !bb.top) {
- final List<RexNode> exprs = new ArrayList<>();
- final RelDataType rowType = bb.root.getRowType();
- final int fieldCount =
- rowType.getFieldCount() - orderExprList.size();
- for (int i = 0; i < fieldCount; i++) {
- exprs.add(rexBuilder.makeInputRef(bb.root, i));
- }
- bb.setRoot(
- LogicalProject.create(bb.root, exprs,
- rowType.getFieldNames().subList(0, fieldCount)),
- false);
- }
- }
-
- /**
- * Returns whether a given node contains a {@link SqlInOperator}.
- *
- * @param node a RexNode tree
- */
- private static boolean containsInOperator(
- SqlNode node) {
- try {
- SqlVisitor<Void> visitor =
- new SqlBasicVisitor<Void>() {
- public Void visit(SqlCall call) {
- if (call.getOperator() instanceof SqlInOperator) {
- throw new Util.FoundOne(call);
- }
- return super.visit(call);
- }
- };
- node.accept(visitor);
- return false;
- } catch (Util.FoundOne e) {
- Util.swallow(e, null);
- return true;
- }
- }
-
- /**
- * Push down all the NOT logical operators into any IN/NOT IN operators.
- *
- * @param scope Scope where {@code sqlNode} occurs
- * @param sqlNode the root node from which to look for NOT operators
- * @return the transformed SqlNode representation with NOT pushed down.
- */
- private static SqlNode pushDownNotForIn(SqlValidatorScope scope,
- SqlNode sqlNode) {
- if ((sqlNode instanceof SqlCall) && containsInOperator(sqlNode)) {
- SqlCall sqlCall = (SqlCall) sqlNode;
- if ((sqlCall.getOperator() == SqlStdOperatorTable.AND)
- || (sqlCall.getOperator() == SqlStdOperatorTable.OR)) {
- SqlNode[] sqlOperands = ((SqlBasicCall) sqlCall).operands;
- for (int i = 0; i < sqlOperands.length; i++) {
- sqlOperands[i] = pushDownNotForIn(scope, sqlOperands[i]);
- }
- return reg(scope, sqlNode);
- } else if (sqlCall.getOperator() == SqlStdOperatorTable.NOT) {
- SqlNode childNode = sqlCall.operand(0);
- assert childNode instanceof SqlCall;
- SqlBasicCall childSqlCall = (SqlBasicCall) childNode;
- if (childSqlCall.getOperator() == SqlStdOperatorTable.AND) {
- SqlNode[] andOperands = childSqlCall.getOperands();
- SqlNode[] orOperands = new SqlNode[andOperands.length];
- for (int i = 0; i < orOperands.length; i++) {
- orOperands[i] = reg(scope,
- SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
- andOperands[i]));
- }
- for (int i = 0; i < orOperands.length; i++) {
- orOperands[i] = pushDownNotForIn(scope, orOperands[i]);
- }
- return reg(scope,
- SqlStdOperatorTable.OR.createCall(SqlParserPos.ZERO,
- orOperands[0], orOperands[1]));
- } else if (childSqlCall.getOperator() == SqlStdOperatorTable.OR) {
- SqlNode[] orOperands = childSqlCall.getOperands();
- SqlNode[] andOperands = new SqlNode[orOperands.length];
- for (int i = 0; i < andOperands.length; i++) {
- andOperands[i] = reg(scope,
- SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
- orOperands[i]));
- }
- for (int i = 0; i < andOperands.length; i++) {
- andOperands[i] = pushDownNotForIn(scope, andOperands[i]);
- }
- return reg(scope,
- SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO,
- andOperands[0], andOperands[1]));
- } else if (childSqlCall.getOperator() == SqlStdOperatorTable.NOT) {
- SqlNode[] notOperands = childSqlCall.getOperands();
- assert notOperands.length == 1;
- return pushDownNotForIn(scope, notOperands[0]);
- } else if (childSqlCall.getOperator() instanceof SqlInOperator) {
- SqlNode[] inOperands = childSqlCall.getOperands();
- SqlInOperator inOp =
- (SqlInOperator) childSqlCall.getOperator();
- if (inOp.isNotIn()) {
- return reg(scope,
- SqlStdOperatorTable.IN.createCall(SqlParserPos.ZERO,
- inOperands[0], inOperands[1]));
- } else {
- return reg(scope,
- SqlStdOperatorTable.NOT_IN.createCall(SqlParserPos.ZERO,
- inOperands[0], inOperands[1]));
- }
- } else {
- // childSqlCall is "leaf" node in a logical expression tree
- // (only considering AND, OR, NOT)
- return sqlNode;
- }
- } else {
- // sqlNode is "leaf" node in a logical expression tree
- // (only considering AND, OR, NOT)
- return sqlNode;
- }
- } else {
- // tree rooted at sqlNode does not contain inOperator
- return sqlNode;
- }
- }
-
- /** Registers with the validator a {@link SqlNode} that has been created
- * during the Sql-to-Rel process. */
- private static SqlNode reg(SqlValidatorScope scope, SqlNode e) {
- scope.getValidator().deriveType(scope, e);
- return e;
- }
-
- /**
- * Converts a WHERE clause.
- *
- * @param bb Blackboard
- * @param where WHERE clause, may be null
- */
- private void convertWhere(
- final Blackboard bb,
- final SqlNode where) {
- if (where == null) {
- return;
- }
- SqlNode newWhere = pushDownNotForIn(bb.scope, where);
- replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
- final RexNode convertedWhere = bb.convertExpression(newWhere);
-
- // only allocate filter if the condition is not TRUE
- if (convertedWhere.isAlwaysTrue()) {
- return;
- }
-
- final RelFactories.FilterFactory factory =
- RelFactories.DEFAULT_FILTER_FACTORY;
- final RelNode filter = factory.createFilter(bb.root, convertedWhere);
- final RelNode r;
- final CorrelationUse p = getCorrelationUse(bb, filter);
- if (p != null) {
- assert p.r instanceof Filter;
- Filter f = (Filter) p.r;
- r = LogicalFilter.create(f.getInput(), f.getCondition(),
- ImmutableSet.of(p.id));
- } else {
- r = filter;
- }
-
- bb.setRoot(r, false);
- }
-
- private void replaceSubQueries(
- final Blackboard bb,
- final SqlNode expr,
- RelOptUtil.Logic logic) {
- findSubQueries(bb, expr, logic, false);
- for (SubQuery node : bb.subQueryList) {
- substituteSubQuery(bb, node);
- }
- }
-
- private void substituteSubQuery(Blackboard bb, SubQuery subQuery) {
- final RexNode expr = subQuery.expr;
- if (expr != null) {
- // Already done.
- return;
- }
-
- final SqlBasicCall call;
- final RelNode rel;
- final SqlNode query;
- final RelOptUtil.Exists converted;
- switch (subQuery.node.getKind()) {
- case CURSOR:
- convertCursor(bb, subQuery);
- return;
-
- case MULTISET_QUERY_CONSTRUCTOR:
- case MULTISET_VALUE_CONSTRUCTOR:
- case ARRAY_QUERY_CONSTRUCTOR:
- rel = convertMultisets(ImmutableList.of(subQuery.node), bb);
- subQuery.expr = bb.register(rel, JoinRelType.INNER);
- return;
-
- case IN:
- call = (SqlBasicCall) subQuery.node;
- query = call.operand(1);
- if (!config.isExpand() && !(query instanceof SqlNodeList)) {
- return;
- }
- final SqlNode leftKeyNode = call.operand(0);
-
- final List<RexNode> leftKeys;
- switch (leftKeyNode.getKind()) {
- case ROW:
- leftKeys = Lists.newArrayList();
- for (SqlNode sqlExpr : ((SqlBasicCall) leftKeyNode).getOperandList()) {
- leftKeys.add(bb.convertExpression(sqlExpr));
- }
- break;
- default:
- leftKeys = ImmutableList.of(bb.convertExpression(leftKeyNode));
- }
-
- final boolean notIn = ((SqlInOperator) call.getOperator()).isNotIn();
- if (query instanceof SqlNodeList) {
- SqlNodeList valueList = (SqlNodeList) query;
- if (!containsNullLiteral(valueList)
- && valueList.size() < config.getInSubQueryThreshold()) {
- // We're under the threshold, so convert to OR.
- subQuery.expr =
- convertInToOr(
- bb,
- leftKeys,
- valueList,
- notIn);
- return;
- }
-
- // Otherwise, let convertExists translate
- // values list into an inline table for the
- // reference to Q below.
- }
-
- // Project out the search columns from the left side
-
- // Q1:
- // "select from emp where emp.deptno in (select col1 from T)"
- //
- // is converted to
- //
- // "select from
- // emp inner join (select distinct col1 from T)) q
- // on emp.deptno = q.col1
- //
- // Q2:
- // "select from emp where emp.deptno not in (Q)"
- //
- // is converted to
- //
- // "select from
- // emp left outer join (select distinct col1, TRUE from T) q
- // on emp.deptno = q.col1
- // where emp.deptno <> null
- // and q.indicator <> TRUE"
- //
- final RelDataType targetRowType =
- SqlTypeUtil.promoteToRowType(typeFactory,
- validator.getValidatedNodeType(leftKeyNode), null);
- converted =
- convertExists(query, RelOptUtil.SubQueryType.IN, subQuery.logic,
- notIn, targetRowType);
- if (converted.indicator) {
- // Generate
- // emp CROSS JOIN (SELECT COUNT(*) AS c,
- // COUNT(deptno) AS ck FROM dept)
- final RelDataType longType =
- typeFactory.createSqlType(SqlTypeName.BIGINT);
- final RelNode seek = converted.r.getInput(0); // fragile
- final int keyCount = leftKeys.size();
- final List<Integer> args = ImmutableIntList.range(0, keyCount);
- LogicalAggregate aggregate =
- LogicalAggregate.create(seek, false, ImmutableBitSet.of(), null,
- ImmutableList.of(
- AggregateCall.create(SqlStdOperatorTable.COUNT, false,
- ImmutableList.<Integer>of(), -1, longType, null),
- AggregateCall.create(SqlStdOperatorTable.COUNT, false,
- args, -1, longType, null)));
- LogicalJoin join =
- LogicalJoin.create(bb.root, aggregate, rexBuilder.makeLiteral(true),
- ImmutableSet.<CorrelationId>of(), JoinRelType.INNER);
- bb.setRoot(join, false);
- }
- final RexNode rex =
- bb.register(converted.r,
- converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER,
- leftKeys);
-
- RelOptUtil.Logic logic = subQuery.logic;
- switch (logic) {
- case TRUE_FALSE_UNKNOWN:
- case UNKNOWN_AS_TRUE:
- if (!converted.indicator) {
- logic = RelOptUtil.Logic.TRUE_FALSE;
- }
- }
- subQuery.expr = translateIn(logic, bb.root, rex);
- if (notIn) {
- subQuery.expr =
- rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
- }
- return;
-
- case EXISTS:
- // "select from emp where exists (select a from T)"
- //
- // is converted to the following if the sub-query is correlated:
- //
- // "select from emp left outer join (select AGG_TRUE() as indicator
- // from T group by corr_var) q where q.indicator is true"
- //
- // If there is no correlation, the expression is replaced with a
- // boolean indicating whether the sub-query returned 0 or >= 1 row.
- call = (SqlBasicCall) subQuery.node;
- query = call.operand(0);
- if (!config.isExpand()) {
- return;
- }
- converted = convertExists(query, RelOptUtil.SubQueryType.EXISTS,
- subQuery.logic, true, null);
- assert !converted.indicator;
- if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
- return;
- }
- subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
- return;
-
- case SCALAR_QUERY:
- // Convert the sub-query. If it's non-correlated, convert it
- // to a constant expression.
- if (!config.isExpand()) {
- return;
- }
- call = (SqlBasicCall) subQuery.node;
- query = call.operand(0);
- converted = convertExists(query, RelOptUtil.SubQueryType.SCALAR,
- subQuery.logic, true, null);
- assert !converted.indicator;
- if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
- return;
- }
- rel = convertToSingleValueSubq(query, converted.r);
- subQuery.expr = bb.register(rel, JoinRelType.LEFT);
- return;
-
- case SELECT:
- // This is used when converting multiset queries:
- //
- // select * from unnest(select multiset[deptno] from emps);
- //
- converted = convertExists(subQuery.node, RelOptUtil.SubQueryType.SCALAR,
- subQuery.logic, true, null);
- assert !converted.indicator;
- subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
- return;
-
- default:
- throw new AssertionError("unexpected kind of sub-query: "
- + subQuery.node);
- }
- }
-
- private RexNode translateIn(RelOptUtil.Logic logic, RelNode root,
- final RexNode rex) {
- switch (logic) {
- case TRUE:
- return rexBuilder.makeLiteral(true);
-
- case TRUE_FALSE:
- case UNKNOWN_AS_FALSE:
- assert rex instanceof RexRangeRef;
- final int fieldCount = rex.getType().getFieldCount();
- RexNode rexNode = rexBuilder.makeFieldAccess(rex, fieldCount - 1);
- rexNode = rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, rexNode);
-
- // Then append the IS NOT NULL(leftKeysForIn).
- //
- // RexRangeRef contains the following fields:
- // leftKeysForIn,
- // rightKeysForIn (the original sub-query select list),
- // nullIndicator
- //
- // The first two lists contain the same number of fields.
- final int k = (fieldCount - 1) / 2;
- for (int i = 0; i < k; i++) {
- rexNode =
- rexBuilder.makeCall(
- SqlStdOperatorTable.AND,
- rexNode,
- rexBuilder.makeCall(
- SqlStdOperatorTable.IS_NOT_NULL,
- rexBuilder.makeFieldAccess(rex, i)));
- }
- return rexNode;
-
- case TRUE_FALSE_UNKNOWN:
- case UNKNOWN_AS_TRUE:
- // select e.deptno,
- // case
- // when ct.c = 0 then false
- // when dt.i is not null then true
- // when e.deptno is null then null
- // when ct.ck < ct.c then null
- // else false
- // end
- // from e
- // cross join (select count(*) as c, count(deptno) as ck from v) as ct
- // left join (select distinct deptno, true as i from v) as dt
- // on e.deptno = dt.deptno
- final Join join = (Join) root;
- final Project left = (Project) join.getLeft();
- final RelNode leftLeft = ((Join) left.getInput()).getLeft();
- final int leftLeftCount = leftLeft.getRowType().getFieldCount();
- final RelDataType longType =
- typeFactory.createSqlType(SqlTypeName.BIGINT);
- final RexNode cRef = rexBuilder.makeInputRef(root, leftLeftCount);
- final RexNode ckRef = rexBuilder.makeInputRef(root, leftLeftCount + 1);
- final RexNode iRef =
- rexBuilder.makeInputRef(root, root.getRowType().getFieldCount() - 1);
-
- final RexLiteral zero =
- rexBuilder.makeExactLiteral(BigDecimal.ZERO, longType);
- final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
- final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
- final RexNode unknownLiteral =
- rexBuilder.makeNullLiteral(trueLiteral.getType());
-
- final ImmutableList.Builder<RexNode> args = ImmutableList.builder();
- args.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, cRef, zero),
- falseLiteral,
- rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, iRef),
- trueLiteral);
- final JoinInfo joinInfo = join.analyzeCondition();
- for (int leftKey : joinInfo.leftKeys) {
- final RexNode kRef = rexBuilder.makeInputRef(root, leftKey);
- args.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, kRef),
- unknownLiteral);
- }
- args.add(rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ckRef, cRef),
- unknownLiteral,
- falseLiteral);
-
- return rexBuilder.makeCall(SqlStdOperatorTable.CASE, args.build());
-
- default:
- throw new AssertionError(logic);
- }
- }
-
- private static boolean containsNullLiteral(SqlNodeList valueList) {
- for (SqlNode node : valueList.getList()) {
- if (node instanceof SqlLiteral) {
- SqlLiteral lit = (SqlLiteral) node;
- if (lit.getValue() == null) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Determines if a sub-query is non-correlated and if so, converts it to a
- * constant.
- *
- * @param subQuery the call that references the sub-query
- * @param bb blackboard used to convert the sub-query
- * @param converted RelNode tree corresponding to the sub-query
- * @param isExists true if the sub-query is part of an EXISTS expression
- * @return Whether the sub-query can be converted to a constant
- */
- private boolean convertNonCorrelatedSubQuery(
- SubQuery subQuery,
- Blackboard bb,
- RelNode converted,
- boolean isExists) {
- SqlCall call = (SqlBasicCall) subQuery.node;
- if (subQueryConverter.canConvertSubQuery()
- && isSubQueryNonCorrelated(converted, bb)) {
- // First check if the sub-query has already been converted
- // because it's a nested sub-query. If so, don't re-evaluate
- // it again.
- RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
- if (constExpr == null) {
- constExpr =
- subQueryConverter.convertSubQuery(
- call,
- this,
- isExists,
- config.isExplain());
- }
- if (constExpr != null) {
- subQuery.expr = constExpr;
- mapConvertedNonCorrSubqs.put(call, constExpr);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Converts the RelNode tree for a select statement to a select that
- * produces a single value.
- *
- * @param query the query
- * @param plan the original RelNode tree corresponding to the statement
- * @return the converted RelNode tree
- */
- public RelNode convertToSingleValueSubq(
- SqlNode query,
- RelNode plan) {
- // Check whether query is guaranteed to produce a single value.
- if (query instanceof SqlSelect) {
- SqlSelect select = (SqlSelect) query;
- SqlNodeList selectList = select.getSelectList();
- SqlNodeList groupList = select.getGroup();
-
- if ((selectList.size() == 1)
- && ((groupList == null) || (groupList.size() == 0))) {
- SqlNode selectExpr = selectList.get(0);
- if (selectExpr instanceof SqlCall) {
- SqlCall selectExprCall = (SqlCall) selectExpr;
- if (Util.isSingleValue(selectExprCall)) {
- return plan;
- }
- }
-
- // If there is a limit with 0 or 1,
- // it is ensured to produce a single value
- if (select.getFetch() != null
- && select.getFetch() instanceof SqlNumericLiteral) {
- SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch();
- if (((BigDecimal) limitNum.getValue()).intValue() < 2) {
- return plan;
- }
- }
- }
- } else if (query instanceof SqlCall) {
- // If the query is (values ...),
- // it is necessary to look into the operands to determine
- // whether SingleValueAgg is necessary
- SqlCall exprCall = (SqlCall) query;
- if (exprCall.getOperator()
- instanceof SqlValuesOperator
- && Util.isSingleValue(exprCall)) {
- return plan;
- }
- }
-
- // If not, project SingleValueAgg
- return RelOptUtil.createSingleValueAggRel(
- cluster,
- plan);
- }
-
- /**
- * Converts "x IN (1, 2, ...)" to "x=1 OR x=2 OR ...".
- *
- * @param leftKeys LHS
- * @param valuesList RHS
- * @param isNotIn is this a NOT IN operator
- * @return converted expression
- */
- private RexNode convertInToOr(
- final Blackboard bb,
- final List<RexNode> leftKeys,
- SqlNodeList valuesList,
- boolean isNotIn) {
- final List<RexNode> comparisons = new ArrayList<>();
- for (SqlNode rightVals : valuesList) {
- RexNode rexComparison;
- if (leftKeys.size() == 1) {
- rexComparison =
- rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
- leftKeys.get(0),
- ensureSqlType(leftKeys.get(0).getType(),
- bb.convertExpression(rightVals)));
- } else {
- assert rightVals instanceof SqlCall;
- final SqlBasicCall call = (SqlBasicCall) rightVals;
- assert (call.getOperator() instanceof SqlRowOperator)
- && call.operandCount() == leftKeys.size();
- rexComparison =
- RexUtil.composeConjunction(
- rexBuilder,
- Iterables.transform(
- Pair.zip(leftKeys, call.getOperandList()),
- new Function<Pair<RexNode, SqlNode>, RexNode>() {
- public RexNode apply(Pair<RexNode, SqlNode> pair) {
- return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
- pair.left,
- ensureSqlType(pair.left.getType(),
- bb.convertExpression(pair.right)));
- }
- }),
- false);
- }
- comparisons.add(rexComparison);
- }
-
- RexNode result =
- RexUtil.composeDisjunction(rexBuilder, comparisons, true);
- assert result != null;
-
- if (isNotIn) {
- result =
- rexBuilder.makeCall(
- SqlStdOperatorTable.NOT,
- result);
- }
-
- return result;
- }
-
- /** Ensures that an expression has a given {@link SqlTypeName}, applying a
- * cast if necessary. If the expression already has the right type family,
- * returns the expression unchanged. */
- private RexNode ensureSqlType(RelDataType type, RexNode node) {
- if (type.getSqlTypeName() == node.getType().getSqlTypeName()
- || (type.getSqlTypeName() == SqlTypeName.VARCHAR
- && node.getType().getSqlTypeName() == SqlTypeName.CHAR)) {
- return node;
- }
- return rexBuilder.ensureType(type, node, true);
- }
-
- /**
- * Gets the list size threshold under which {@link #convertInToOr} is used.
- * Lists of this size or greater will instead be converted to use a join
- * against an inline table
- * ({@link org.apache.calcite.rel.logical.LogicalValues}) rather than a
- * predicate. A threshold of 0 forces usage of an inline table in all cases; a
- * threshold of Integer.MAX_VALUE forces usage of OR in all cases
- *
- * @return threshold, default {@link #DEFAULT_IN_SUB_QUERY_THRESHOLD}
- */
- @Deprecated // to be removed before 2.0
- protected int getInSubqueryThreshold() {
- return config.getInSubQueryThreshold();
- }
-
- /**
- * Converts an EXISTS or IN predicate into a join. For EXISTS, the sub-query
- * produces an indicator variable, and the result is a relational expression
- * which outer joins that indicator to the original query. After performing
- * the outer join, the condition will be TRUE if the EXISTS condition holds,
- * NULL otherwise.
- *
- * @param seek A query, for example 'select * from emp' or
- * 'values (1,2,3)' or '('Foo', 34)'.
- * @param subQueryType Whether sub-query is IN, EXISTS or scalar
- * @param logic Whether the answer needs to be in full 3-valued logic (TRUE,
- * FALSE, UNKNOWN) will be required, or whether we can accept an
- * approximation (say representing UNKNOWN as FALSE)
- * @param notIn Whether the operation is NOT IN
- * @return join expression
- */
- private RelOptUtil.Exists convertExists(
- SqlNode seek,
- RelOptUtil.SubQueryType subQueryType,
- RelOptUtil.Logic logic,
- boolean notIn,
- RelDataType targetDataType) {
- final SqlValidatorScope seekScope =
- (seek instanceof SqlSelect)
- ? validator.getSelectScope((SqlSelect) seek)
- : null;
- final Blackboard seekBb = createBlackboard(seekScope, null, false);
- RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
-
- return RelOptUtil.createExistsPlan(seekRel, subQueryType, logic, notIn);
- }
-
- private RelNode convertQueryOrInList(
- Blackboard bb,
- SqlNode seek,
- RelDataType targetRowType) {
- // NOTE: Once we start accepting single-row queries as row constructors,
- // there will be an ambiguity here for a case like X IN ((SELECT Y FROM
- // Z)). The SQL standard resolves the ambiguity by saying that a lone
- // select should be interpreted as a table expression, not a row
- // expression. The semantic difference is that a table expression can
- // return multiple rows.
- if (seek instanceof SqlNodeList) {
- return convertRowValues(
- bb,
- seek,
- ((SqlNodeList) seek).getList(),
- false,
- targetRowType);
- } else {
- return convertQueryRecursive(seek, false, null).project();
- }
- }
-
- private RelNode convertRowValues(
- Blackboard bb,
- SqlNode rowList,
- Collection<SqlNode> rows,
- boolean allowLiteralsOnly,
- RelDataType targetRowType) {
- // NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
- // literals into a single LogicalValues; this gives the optimizer a smaller
- // input tree. For everything else (computed expressions, row
- // sub-queries), we union each row in as a projection on top of a
- // LogicalOneRow.
-
- final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList =
- ImmutableList.builder();
- final RelDataType rowType;
- if (targetRowType != null) {
- rowType = targetRowType;
- } else {
- rowType =
- SqlTypeUtil.promoteToRowType(
- typeFactory,
- validator.getValidatedNodeType(rowList),
- null);
- }
-
- final List<RelNode> unionInputs = new ArrayList<>();
- for (SqlNode node : rows) {
- SqlBasicCall call;
- if (isRowConstructor(node)) {
- call = (SqlBasicCall) node;
- ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
- for (Ord<SqlNode> operand : Ord.zip(call.operands)) {
- RexLiteral rexLiteral =
- convertLiteralInValuesList(
- operand.e,
- bb,
- rowType,
- operand.i);
- if ((rexLiteral == null) && allowLiteralsOnly) {
- return null;
- }
- if ((rexLiteral == null) || !config.isCreateValuesRel()) {
- // fallback to convertRowConstructor
- tuple = null;
- break;
- }
- tuple.add(rexLiteral);
- }
- if (tuple != null) {
- tupleList.add(tuple.build());
- continue;
- }
- } else {
- RexLiteral rexLiteral =
- convertLiteralInValuesList(
- node,
- bb,
- rowType,
- 0);
- if ((rexLiteral != null) && config.isCreateValuesRel()) {
- tupleList.add(ImmutableList.of(rexLiteral));
- continue;
- } else {
- if ((rexLiteral == null) && allowLiteralsOnly) {
- return null;
- }
- }
-
- // convert "1" to "row(1)"
- call =
- (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(
- SqlParserPos.ZERO,
- node);
- }
- unionInputs.add(convertRowConstructor(bb, call));
- }
- LogicalValues values =
- LogicalValues.create(cluster, rowType, tupleList.build());
- RelNode resultRel;
- if (unionInputs.isEmpty()) {
- resultRel = values;
- } else {
- if (!values.getTuples().isEmpty()) {
- unionInputs.add(values);
- }
- resultRel = LogicalUnion.create(unionInputs, true);
- }
- leaves.add(resultRel);
- return resultRel;
- }
-
- private RexLiteral convertLiteralInValuesList(
- SqlNode sqlNode,
- Blackboard bb,
- RelDataType rowType,
- int iField) {
- if (!(sqlNode instanceof SqlLiteral)) {
- return null;
- }
- RelDataTypeField field = rowType.getFieldList().get(iField);
- RelDataType type = field.getType();
- if (type.isStruct()) {
- // null literals for weird stuff like UDT's need
- // special handling during type flattening, so
- // don't use LogicalValues for those
- return null;
- }
-
- RexNode literalExpr =
- exprConverter.convertLiteral(
- bb,
- (SqlLiteral) sqlNode);
-
- if (!(literalExpr instanceof RexLiteral)) {
- assert literalExpr.isA(SqlKind.CAST);
- RexNode child = ((RexCall) literalExpr).getOperands().get(0);
- assert RexLiteral.isNullLiteral(child);
-
- // NOTE jvs 22-Nov-2006: we preserve type info
- // in LogicalValues digest, so it's OK to lose it here
- return (RexLiteral) child;
- }
-
- RexLiteral literal = (RexLiteral) literalExpr;
-
- Comparable value = literal.getValue();
-
- if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.hasScale(type)) {
- BigDecimal roundedValue =
- NumberUtil.rescaleBigDecimal(
- (BigDecimal) value,
- type.getScale());
- return rexBuilder.makeExactLiteral(
- roundedValue,
- type);
- }
-
- if ((value instanceof NlsString)
- && (type.getSqlTypeName() == SqlTypeName.CHAR)) {
- // pad fixed character type
- NlsString unpadded = (NlsString) value;
- return rexBuilder.makeCharLiteral(
- new NlsString(
- Spaces.padRight(unpadded.getValue(), type.getPrecision()),
- unpadded.getCharsetName(),
- unpadded.getCollation()));
- }
- return literal;
- }
-
- private boolean isRowConstructor(SqlNode node) {
- if (!(node.getKind() == SqlKind.ROW)) {
- return false;
- }
- SqlCall call = (SqlCall) node;
- return call.getOperator().getName().equalsIgnoreCase("row");
- }
-
- /**
- * Builds a list of all <code>IN</code> or <code>EXISTS</code> operators
- * inside SQL parse tree. Does not traverse inside queries.
- *
- * @param bb blackboard
- * @param node the SQL parse tree
- * @param logic Whether the answer needs to be in full 3-valued logic (TRUE,
- * FALSE, UNKNOWN) will be required, or whether we can accept
- * an approximation (say representing UNKNOWN as FALSE)
- * @param registerOnlyScalarSubQueries if set to true and the parse tree
- * corresponds to a variation of a select
- * node, only register it if it's a scalar
- * sub-query
- */
- private void findSubQueries(
- Blackboard bb,
- SqlNode node,
- RelOptUtil.Logic logic,
- boolean registerOnlyScalarSubQueries) {
- final SqlKind kind = node.getKind();
- switch (kind) {
- case EXISTS:
- case SELECT:
- case MULTISET_QUERY_CONSTRUCTOR:
- case MULTISET_VALUE_CONSTRUCTOR:
- case ARRAY_QUERY_CONSTRUCTOR:
- case CURSOR:
- case SCALAR_QUERY:
- if (!registerOnlyScalarSubQueries
- || (kind == SqlKind.SCALAR_QUERY)) {
- bb.registerSubQuery(node, RelOptUtil.Logic.TRUE_FALSE);
- }
- return;
- case IN:
- if (((SqlCall) node).getOperator() == SqlStdOperatorTable.NOT_IN) {
- logic = logic.negate();
- }
- break;
- case NOT:
- logic = logic.negate();
- break;
- }
- if (node instanceof SqlCall) {
- for (SqlNode operand : ((SqlCall) node).getOperandList()) {
- if (operand != null) {
- // In the case of an IN expression, locate scalar
- // sub-queries so we can convert them to constants
- findSubQueries(
- bb,
- operand,
- logic,
- kind == SqlKind.IN || registerOnlyScalarSubQueries);
- }
- }
- } else if (node instanceof SqlNodeList) {
- for (SqlNode child : (SqlNodeList) node) {
- findSubQueries(
- bb,
- child,
- logic,
- kind == SqlKind.IN || registerOnlyScalarSubQueries);
- }
- }
-
- // Now that we've located any scalar sub-queries inside the IN
- // expression, register the IN expression itself. We need to
- // register the scalar sub-queries first so they can be converted
- // before the IN expression is converted.
- if (kind == SqlKind.IN) {
- switch (logic) {
- case TRUE_FALSE_UNKNOWN:
- if (validator.getValidatedNodeType(node).isNullable()) {
- break;
- } else if (true) {
- break;
- }
- // fall through
- case UNKNOWN_AS_FALSE:
- logic = RelOptUtil.Logic.TRUE;
- }
- bb.registerSubQuery(node, logic);
- }
- }
-
- /**
- * Converts an expression from {@link SqlNode} to {@link RexNode} format.
- *
- * @param node Expression to translate
- * @return Converted expression
- */
- public RexNode convertExpression(
- SqlNode node) {
- Map<String, RelDataType> nameToTypeMap = Collections.emptyMap();
- final ParameterScope scope =
- new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
- final Blackboard bb = createBlackboard(scope, null, false);
- return bb.convertExpression(node);
- }
-
- /**
- * Converts an expression from {@link SqlNode} to {@link RexNode} format,
- * mapping identifier references to predefined expressions.
- *
- * @param node Expression to translate
- * @param nameToNodeMap map from String to {@link RexNode}; when an
- * {@link SqlIdentifier} is encountered, it is used as a
- * key and translated to the corresponding value from
- * this map
- * @return Converted expression
- */
- public RexNode convertExpression(
- SqlNode node,
- Map<String, RexNode> nameToNodeMap) {
- final Map<String, RelDataType> nameToTypeMap = new HashMap<>();
- for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
- nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
- }
- final ParameterScope scope =
- new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
- final Blackboard bb = createBlackboard(scope, nameToNodeMap, false);
- return bb.convertExpression(node);
- }
-
- /**
- * Converts a non-standard expression.
- *
- * <p>This method is an extension-point that derived classes can override. If
- * this method returns a null result, the normal expression translation
- * process will proceed. The default implementation always returns null.
- *
- * @param node Expression
- * @param bb Blackboard
- * @return null to proceed with the usual expression translation process
- */
- protected RexNode convertExtendedExpression(
- SqlNode node,
- Blackboard bb) {
- return null;
- }
-
- private RexNode convertOver(Blackboard bb, SqlNode node) {
- SqlCall call = (SqlCall) node;
- SqlCall aggCall = call.operand(0);
- SqlNode windowOrRef = call.operand(1);
- final SqlWindow window =
- validator.resolveWindow(windowOrRef, bb.scope, true);
-
- // ROW_NUMBER() expects specific kind of framing.
- if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
- window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
- window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
- window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
- }
- final SqlNodeList partitionList = window.getPartitionList();
- final ImmutableList.Builder<RexNode> partitionKeys =
- ImmutableList.builder();
- for (SqlNode partition : partitionList) {
- partitionKeys.add(bb.convertExpression(partition));
- }
- RexNode lowerBound = bb.convertExpression(window.getLowerBound());
- RexNode upperBound = bb.convertExpression(window.getUpperBound());
- SqlNodeList orderList = window.getOrderList();
- if ((orderList.size() == 0) && !window.isRows()) {
- // A logical range requires an ORDER BY clause. Use the implicit
- // ordering of this relation. There must be one, otherwise it would
- // have failed validation.
- orderList = bb.scope.getOrderList();
- if (orderList == null) {
- throw new AssertionError(
- "Relation should have sort key for implicit ORDER BY");
- }
- }
- final ImmutableList.Builder<RexFieldCollation> orderKeys =
- ImmutableList.builder();
- final Set<SqlKind> flags = EnumSet.noneOf(SqlKind.class);
- for (SqlNode order : orderList) {
- flags.clear();
- RexNode e = bb.convertSortExpression(order, flags);
- orderKeys.add(new RexFieldCollation(e, flags));
- }
- try {
- Preconditions.checkArgument(bb.window == null,
- "already in window agg mode");
- bb.window = window;
- RexNode rexAgg = exprConverter.convertCall(bb, aggCall);
- rexAgg =
- rexBuilder.ensureType(
- validator.getValidatedNodeType(call), rexAgg, false);
-
- // Walk over the tree and apply 'over' to all agg functions. This is
- // necessary because the returned expression is not necessarily a call
- // to an agg function. For example, AVG(x) becomes SUM(x) / COUNT(x).
-
- boolean isDistinct = false;
- if (aggCall.getFunctionQuantifier() != null
- && aggCall.getFunctionQuantifier().getValue().equals(SqlSelectKeyword.DISTINCT)) {
- isDistinct = true;
- }
-
- final RexShuttle visitor =
- new HistogramShuttle(
- partitionKeys.build(), orderKeys.build(),
- RexWindowBound.create(window.getLowerBound(), lowerBound),
- RexWindowBound.create(window.getUpperBound(), upperBound),
- window,
- isDistinct);
- RexNode overNode = rexAgg.accept(visitor);
-
- return overNode;
- } finally {
- bb.window = null;
- }
- }
-
- /**
- * Converts a FROM clause into a relational expression.
- *
- * @param bb Scope within which to resolve identifiers
- * @param from FROM clause of a query. Examples include:
- *
- * <ul>
- * <li>a single table ("SALES.EMP"),
- * <li>an aliased table ("EMP AS E"),
- * <li>a list of tables ("EMP, DEPT"),
- * <li>an ANSI Join expression ("EMP JOIN DEPT ON EMP.DEPTNO =
- * DEPT.DEPTNO"),
- * <li>a VALUES clause ("VALUES ('Fred', 20)"),
- * <li>a query ("(SELECT * FROM EMP WHERE GENDER = 'F')"),
- * <li>or any combination of the above.
- * </ul>
- */
- protected void convertFrom(
- Blackboard bb,
- SqlNode from) {
- if (from == null) {
- bb.setRoot(LogicalValues.createOneRow(cluster), false);
- return;
- }
-
- final SqlCall call;
- final SqlNode[] operands;
- switch (from.getKind()) {
- case MATCH_RECOGNIZE:
- convertMatchRecognize(bb, (SqlCall) from);
- return;
-
- case AS:
- convertFrom(bb, ((SqlCall) from).operand(0));
- return;
-
- case WITH_ITEM:
- convertFrom(bb, ((SqlWithItem) from).query);
- return;
-
- case WITH:
- convertFrom(bb, ((SqlWith) from).body);
- return;
-
- case TABLESAMPLE:
- operands = ((SqlBasicCall) from).getOperands();
- SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
- if (sampleSpec instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
- String sampleName =
- ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec)
- .getName();
- datasetStack.push(sampleName);
- convertFrom(bb, operands[0]);
- datasetStack.pop();
- } else if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
- SqlSampleSpec.SqlTableSampleSpec tableSampleSpec =
- (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
- convertFrom(bb, operands[0]);
- RelOptSamplingParameters params =
- new RelOptSamplingParameters(
- tableSampleSpec.isBernoulli(),
- tableSampleSpec.getSamplePercentage(),
- tableSampleSpec.isRepeatable(),
- tableSampleSpec.getRepeatableSeed());
- bb.setRoot(new Sample(cluster, bb.root, params), false);
- } else {
- throw new AssertionError("unknown TABLESAMPLE type: " + sampleSpec);
- }
- return;
-
- case IDENTIFIER:
- convertIdentifier(bb, (SqlIdentifier) from, null);
- return;
-
- case EXTEND:
- call = (SqlCall) from;
- SqlIdentifier id = (SqlIdentifier) call.getOperandList().get(0);
- SqlNodeList extendedColumns = (SqlNodeList) call.getOperandList().get(1);
- convertIdentifier(bb, id, extendedColumns);
- return;
-
- case JOIN:
- final SqlJoin join = (SqlJoin) from;
- final SqlValidatorScope scope = validator.getJoinScope(from);
- final Blackboard fromBlackboard = createBlackboard(scope, null, false);
- SqlNode left = join.getLeft();
- SqlNode right = join.getRight();
- final boolean isNatural = join.isNatural();
- final JoinType joinType = join.getJoinType();
- final SqlValidatorScope leftScope =
- Util.first(validator.getJoinScope(left),
- ((DelegatingScope) bb.scope).getParent());
- final Blackboard leftBlackboard =
- createBlackboard(leftScope, null, false);
- final SqlValidatorScope rightScope =
- Util.first(validator.getJoinScope(right),
- ((DelegatingScope) bb.scope).getParent());
- final Blackboard rightBlackboard =
- createBlackboard(rightScope, null, false);
- convertFrom(leftBlackboard, left);
- RelNode leftRel = leftBlackboard.root;
- convertFrom(rightBlackboard, right);
- RelNode rightRel = rightBlackboard.root;
- JoinRelType convertedJoinType = convertJoinType(joinType);
- RexNode conditionExp;
- final SqlValidatorNamespace leftNamespace = validator.getNamespace(left);
- final SqlValidatorNamespace rightNamespace = validator.getNamespace(right);
- if (isNatural) {
- final RelDataType leftRowType = leftNamespace.getRowType();
- final RelDataType rightRowType = rightNamespace.getRowType();
- final List<String> columnList =
- SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType,
- rightRowType);
- conditionExp = convertUsing(leftNamespace, rightNamespace,
- columnList);
- } else {
- conditionExp =
- convertJoinCondition(
- fromBlackboard,
- leftNamespace,
- rightNamespace,
- join.getCondition(),
- join.getConditionType(),
- leftRel,
- rightRel);
- }
-
- final RelNode joinRel =
- createJoin(
- fromBlackboard,
- leftRel,
- rightRel,
- conditionExp,
- convertedJoinType);
- bb.setRoot(joinRel, false);
- return;
-
- case SELECT:
- case INTERSECT:
- case EXCEPT:
- case UNION:
- final RelNode rel = convertQueryRecursive(from, false, null).project();
- bb.setRoot(rel, true);
- return;
-
- case VALUES:
- convertValuesImpl(bb, (SqlCall) from, null);
- return;
-
- case UNNEST:
- call = (SqlCall) from;
- final List<SqlNode> nodes = call.getOperandList();
- final SqlUnnestOperator operator = (SqlUnnestOperator) call.getOperator();
- for (SqlNode node : nodes) {
- replaceSubQueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
- }
- final List<RexNode> exprs = new ArrayList<>();
- final List<String> fieldNames = new ArrayList<>();
- for (Ord<SqlNode> node : Ord.zip(nodes)) {
- exprs.add(bb.convertExpression(node.e));
- fieldNames.add(validator.deriveAlias(node.e, node.i));
- }
- final RelNode input =
- RelOptUtil.createProject(
- (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster),
- exprs, fieldNames, true);
-
- Uncollect uncollect =
- new Uncollect(cluster, cluster.traitSetOf(Convention.NONE),
- input, operator.withOrdinality);
- bb.setRoot(uncollect, true);
- return;
-
- case COLLECTION_TABLE:
- call = (SqlCall) from;
-
- // Dig out real call; TABLE() wrapper is just syntactic.
- assert call.getOperandList().size() == 1;
- final SqlCall call2 = call.operand(0);
- convertCollectionTable(bb, call2);
- return;
-
- default:
- throw new AssertionError("not a join operator " + from);
- }
- }
-
- protected void convertMatchRecognize(Blackboard bb, SqlCall call) {
- final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
- final SqlValidatorNamespace ns = validator.getNamespace(matchRecognize);
- final SqlValidatorScope scope = validator.getMatchRecognizeScope(matchRecognize);
-
- final Blackboard matchBb = createBlackboard(scope, null, false);
- final RelDataType rowType = ns.getRowType();
- // convert inner query, could be a table name or a derived table
- SqlNode expr = matchRecognize.getTableRef();
- convertFrom(matchBb, expr);
- final RelNode input = matchBb.root;
-
- // PARTITION BY
- final SqlNodeList partitionList = matchRecognize.getPartitionList();
- final List<RexNode> partitionKeys = new ArrayList<>();
- for (SqlNode partition : partitionList) {
- RexNode e = matchBb.convertExpression(partition);
- partitionKeys.add(e);
- }
-
- // ORDER BY
- final SqlNodeList orderList = matchRecognize.getOrderList();
- final List<RelFieldCollation> orderKeys = new ArrayList<>();
- for (SqlNode order : orderList) {
- final RelFieldCollation.Direction direction;
- switch (order.getKind()) {
- case DESCENDING:
- direction = RelFieldCollation.Direction.DESCENDING;
- order = ((SqlCall) order).operand(0);
- break;
- case NULLS_FIRST:
- case NULLS_LAST:
- throw new AssertionError();
- default:
- direction = RelFieldCollation.Direction.ASCENDING;
- break;
- }
- final RelFieldCollation.NullDirection nullDirection =
- validator.getDefaultNullCollation().last(desc(direction))
- ? RelFieldCollation.NullDirection.LAST
- : RelFieldCollation.NullDirection.FIRST;
- RexNode e = matchBb.convertExpression(order);
- orderKeys.add(
- new RelFieldCollation(((RexInputRef) e).getIndex(), direction,
- nullDirection));
- }
- final RelCollation orders = cluster.traitSet().canonize(RelCollations.of(orderKeys));
-
- // convert pattern
- final Set<String> patternVarsSet = new HashSet<>();
- SqlNode pattern = matchRecognize.getPattern();
- final SqlBasicVisitor<RexNode> patternVarVisitor =
- new SqlBasicVisitor<RexNode>() {
- @Override public RexNode visit(SqlCall call) {
- List<SqlNode> operands = call.getOperandList();
- List<RexNode> newOperands = Lists.newArrayList();
- for (SqlNode node : operands) {
- newOperands.add(node.accept(this));
- }
- return rexBuilder.makeCall(
- validator.getUnknownType(), call.getOperator(), newOperands);
- }
-
- @Override public RexNode visit(SqlIdentifier id) {
- assert id.isSimple();
- patternVarsSet.add(id.getSimple());
- return rexBuilder.makeLiteral(id.getSimple());
- }
-
- @Override public RexNode visit(SqlLiteral literal) {
- if (literal instanceof SqlNumericLiteral) {
- return rexBuilder.makeExactLiteral(BigDecimal.valueOf(literal.intValue(true)));
- } else {
- return rexBuilder.makeLiteral(literal.booleanValue());
- }
- }
- };
- final RexNode patternNode = pattern.accept(patternVarVisitor);
-
- // convert subset
- final SqlNodeList subsets = matchRecognize.getSubsetList();
- final Map<String, TreeSet<String>> subsetMap = Maps.newHashMap();
- for (SqlNode node : subsets) {
- List<SqlNode> operands = ((SqlCall) node).getOperandList();
- SqlIdentifier left = (SqlIdentifier) operands.get(0);
- patternVarsSet.add(left.getSimple());
- SqlNodeList rights = (SqlNodeList) operands.get(1);
- final TreeSet<String> list = new TreeSet<String>();
- for (SqlNode right : rights) {
- assert right instanceof SqlIdentifier;
- list.add(((SqlIdentifier) right).getSimple());
- }
- subsetMap.put(left.getSimple(), list);
- }
-
- SqlNode afterMatch = matchRecognize.getAfter();
- if (afterMatch == null) {
- afterMatch =
- SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW.symbol(SqlParserPos.ZERO);
- }
-
- final RexNode after;
- if (afterMatch instanceof SqlCall) {
- List<SqlNode> operands = ((SqlCall) afterMatch).getOperandList();
- SqlOperator operator = ((SqlCall) afterMatch).getOperator();
- assert operands.size() == 1;
- SqlIdentifier id = (SqlIdentifier) operands.get(0);
- assert patternVarsSet.contains(id.getSimple())
- : id.getSimple() + " not defined in pattern";
- RexNode rex = rexBuilder.makeLiteral(id.getSimple());
- after =
- rexBuilder.makeCall(validator.getUnknownType(), operator,
- ImmutableList.of(rex));
- } else {
- after = matchBb.convertExpression(afterMatch);
- }
-
- matchBb.setPatternVarRef(true);
-
- // convert measures
- final ImmutableMap.Builder<String, RexNode> measureNodes =
- ImmutableMap.builder();
- for (SqlNode measure : matchRecognize.getMeasureList()) {
- List<SqlNode> operands = ((SqlCall) measure).getOperandList();
- String alias = ((SqlIdentifier) operands.get(1)).getSimple();
- RexNode rex = matchBb.convertExpression(operands.get(0));
- measureNodes.put(alias, rex);
- }
-
- // convert definitions
- final ImmutableMap.Builder<String, RexNode> definitionNodes =
- ImmutableMap.builder();
- for (SqlNode def : matchRecognize.getPatternDefList()) {
- List<SqlNode> operands = ((SqlCall) def).getOperandList();
- String alias = ((SqlIdentifier) operands.get(1)).getSimple();
- RexNode rex = matchBb.convertExpression(operands.get(0));
- definitionNodes.put(alias, rex);
- }
-
- final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
- final boolean allRows = rowsPerMatch != null
- && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
-
- matchBb.setPatternVarRef(false);
-
- final RelFactories.MatchFactory factory =
- RelFactories.DEFAULT_MATCH_FACTORY;
- final RelNode rel =
- factory.createMatchRecognize(input, patternNode,
- matchRecognize.getStrictStart().booleanValue(),
- matchRecognize.getStrictEnd().booleanValue(),
- definitionNodes.build(), measureNodes.build(), after,
- subsetMap, allRows, partitionKeys, orders, rowType);
- bb.setRoot(rel, false);
- }
-
- private void convertIdentifier(Blackboard bb, SqlIdentifier id,
- SqlNodeList extendedColumns) {
- final SqlValidatorNamespace fromNamespace =
- validator.getNamespace(id).resolve();
- if (fromNamespace.getNode() != null) {
- convertFrom(bb, fromNamespace.getNode());
- return;
- }
- final String datasetName =
- datasetStack.isEmpty() ? null : datasetStack.peek();
- final boolean[] usedDataset = {false};
- RelOptTable table =
- SqlValidatorUtil.getRelOptTable(fromNamespace, catalogReader,
- datasetName, usedDataset);
- if (extendedColumns != null && extendedColumns.size() > 0) {
- assert table != null;
- final SqlValidatorTable validatorTable =
- table.unwrap(SqlValidatorTable.class);
- final List<RelDataTypeField> extendedFields =
- SqlValidatorUtil.getExtendedColumns(validator.getTypeFactory(), validatorTable,
- extendedColumns);
- table = table.extend(extendedFields);
- }
- final RelNode tableRel;
- if (config.isConvertTableAccess()) {
- tableRel = toRel(table);
- } else {
- tableRel = LogicalTableScan.create(cluster, table);
- }
- bb.setRoot(tableRel, true);
- if (usedDataset[0]) {
- bb.setDataset(datasetName);
- }
- }
-
- protected void convertCollectionTable(
- Blackboard bb,
- SqlCall call) {
- final SqlOperator operator = call.getOperator();
- if (operator == SqlStdOperatorTable.TABLESAMPLE) {
- final String sampleName = (String) SqlLiteral.value(call.operand(0));
- datasetStack.push(sampleName);
- SqlCall cursorCall = call.operand(1);
- SqlNode query = cursorCall.operand(0);
- RelNode converted = convertQuery(query, false, false).rel;
- bb.setRoot(converted, false);
- datasetStack.pop();
- return;
- }
- replaceSubQueries(bb, call, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-
- // Expand table macro if possible. It's more efficient than
- // LogicalTableFunctionScan.
- final SqlCallBinding callBinding =
- new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
- if (operator instanceof SqlUserDefinedTableMacro) {
- final SqlUserDefinedTableMacro udf =
- (SqlUserDefinedTableMacro) operator;
- final TranslatableTable table =
- udf.getTable(typeFactory, callBinding.operands());
- final RelDataType rowType = table.getRowType(typeFactory);
- RelOptTable relOptTable = RelOptTableImpl.create(null, rowType, table,
- udf.getNameAsId().names);
- RelNode converted = toRel(relOptTable);
- bb.setRoot(converted, true);
- return;
- }
-
- Type elementType;
- if (operator instanceof SqlUserDefinedTableFunction) {
- SqlUserDefinedTableFunction udtf = (SqlUserDefinedTableFunction) operator;
- elementType = udtf.getElementType(typeFactory, callBinding.operands());
- } else {
- elementType = null;
- }
-
- RexNode rexCall = bb.convertExpression(call);
- final List<RelNode> inputs = bb.retrieveCursors();
- Set<RelColumnMapping> columnMappings =
- getColumnMappings(operator);
- LogicalTableFunctionScan callRel =
- LogicalTableFunctionScan.create(
- cluster,
- inputs,
- rexCall,
- elementType,
- validator.getValidatedNodeType(call),
- columnMappings);
- bb.setRoot(callRel, true);
- afterTableFunction(bb, call, callRel);
- }
-
- protected void afterTableFunction(
- SqlToRelConverter.Blackboard bb,
- SqlCall call,
- LogicalTableFunctionScan callRel) {
- }
-
- private Set<RelColumnMapping> getColumnMappings(SqlOperator op) {
- SqlReturnTypeInference rti = op.getReturnTypeInference();
- if (rti == null) {
- return null;
- }
- if (rti instanceof TableFunctionReturnTypeInference) {
- TableFunctionReturnTypeInference tfrti =
- (TableFunctionReturnTypeInference) rti;
- return tfrti.getColumnMappings();
- } else {
- return null;
- }
- }
-
- protected RelNode createJoin(
- Blackboard bb,
- RelNode leftRel,
- RelNode rightRel,
- RexNode joinCond,
- JoinRelType joinType) {
- assert joinCond != null;
-
- final CorrelationUse p = getCorrelationUse(bb, rightRel);
- if (p != null) {
- LogicalCorrelate corr = LogicalCorrelate.create(leftRel, p.r,
- p.id, p.requiredColumns, SemiJoinType.of(joinType));
- if (!joinCond.isAlwaysTrue()) {
- final RelFactories.FilterFactory factory =
- RelFactories.DEFAULT_FILTER_FACTORY;
- return factory.createFilter(corr, joinCond);
- }
- return corr;
- }
-
- // OVERRIDE POINT
- if (containOnlyCast(joinCond)) {
- joinCond = convertCastCondition(joinCond);
- }
-
- final Join originalJoin =
- (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(leftRel, rightRel,
- joinCond, ImmutableSet.<CorrelationId>of(), joinType, false);
-
- return RelOptUtil.pushDownJoinConditions(originalJoin);
- }
-
- // OVERRIDE POINT
- private boolean containOnlyCast(RexNode node) {
- boolean result = true;
- switch (node.getKind()) {
- case AND:
- case EQUALS:
- final RexCall call = (RexCall) node;
- List<RexNode> operands = Lists.newArrayList(call.getOperands());
- for (int i = 0; i < operands.size(); i++) {
- RexNode operand = operands.get(i);
- result &= containOnlyCast(operand);
- }
- break;
- case OR:
- case INPUT_REF:
- case LITERAL:
- case CAST:
- return true;
- default:
- return false;
- }
- return result;
- }
-
- // OVERRIDE POINT
- private static RexNode convertCastCondition(RexNode node) {
- switch (node.getKind()) {
- case IS_NULL:
- case IS_NOT_NULL:
- case OR:
- case AND:
- case EQUALS:
- RexCall call = (RexCall) node;
- List<RexNode> list = Lists.newArrayList();
- List<RexNode> operands = Lists.newArrayList(call.getOperands());
- for (int i = 0; i < operands.size(); i++) {
- RexNode operand = operands.get(i);
- final RexNode e =
- convertCastCondition(
- operand);
- list.add(e);
- }
- if (!list.equals(call.getOperands())) {
- return call.clone(call.getType(), list);
- }
- return call;
- case CAST:
- call = (RexCall) node;
- operands = Lists.newArrayList(call.getOperands());
- return operands.get(0);
- default:
- return node;
- }
- }
-
- private CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0) {
- final Set<CorrelationId> correlatedVariables =
- RelOptUtil.getVariablesUsed(r0);
- if (correlatedVariables.isEmpty()) {
- return null;
- }
- final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
- final List<CorrelationId> correlNames = Lists.newArrayList();
-
- // All correlations must refer the same namespace since correlation
- // produces exactly one correlation source.
- // The same source might be referenced by different variables since
- // DeferredLookups are not de-duplicated at create time.
- SqlValidatorNamespace prevNs = null;
-
- for (CorrelationId correlName : correlatedVariables) {
- DeferredLookup lookup =
- mapCorrelToDeferred.get(correlName);
- RexFieldAccess fieldAccess = lookup.getFieldAccess(correlName);
- String originalRelName = lookup.getOriginalRelName();
- String originalFieldName = fieldAccess.getField().getName();
-
- final SqlNameMatcher nameMatcher =
- lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
- final SqlValidatorScope.ResolvedImpl resolved =
- new SqlValidatorScope.ResolvedImpl();
- lookup.bb.scope.resolve(ImmutableList.of(originalRelName),
- nameMatcher, false, resolved);
- assert resolved.count() == 1;
- final SqlValidatorScope.Resolve resolve = resolved.only();
- final SqlValidatorNamespace foundNs = resolve.namespace;
- final RelDataType rowType = resolve.rowType();
- final int childNamespaceIndex = resolve.path.steps().get(0).i;
- final SqlValidatorScope ancestorScope = resolve.scope;
- boolean correlInCurrentScope = ancestorScope == bb.scope;
-
- if (!correlInCurrentScope) {
- continue;
- }
-
- if (prevNs == null) {
- prevNs = foundNs;
- } else {
- assert prevNs == foundNs : "All correlation variables should resolve"
- + " to the same namespace."
- + " Prev ns=" + prevNs
- + ", new ns=" + foundNs;
- }
-
- int namespaceOffset = 0;
- if (childNamespaceIndex > 0) {
- // If not the first child, need to figure out the width
- // of output types from all the preceding namespaces
- assert ancestorScope instanceof ListScope;
- List<SqlValidatorNamespace> children =
- ((ListScope) ancestorScope).getChildren();
-
- for (int i = 0; i < childNamespaceIndex; i++) {
- SqlValidatorNamespace child = children.get(i);
- namespaceOffset +=
- child.getRowType().getFieldCount();
- }
- }
-
- RexFieldAccess topLevelFieldAccess = fieldAccess;
- while (topLevelFieldAccess.getReferenceExpr() instanceof RexFieldAccess) {
- topLevelFieldAccess = (RexFieldAccess) topLevelFieldAccess.getReferenceExpr();
- }
- final RelDataTypeField field = rowType.getFieldList()
- .get(topLevelFieldAccess.getField().getIndex() - namespaceOffset);
- int pos = namespaceOffset + field.getIndex();
-
- assert field.getType()
- == topLevelFieldAccess.getField().getType();
-
- assert pos != -1;
-
- if (bb.mapRootRelToFieldProjection.containsKey(bb.root)) {
- // bb.root is an aggregate and only projects group by
- // keys.
- Map<Integer, Integer> exprProjection =
- bb.mapRootRelToFieldProjection.get(bb.root);
-
- // sub-query can reference group by keys projected from
- // the root of the outer relation.
- if (exprProjection.containsKey(pos)) {
- pos = exprProjection.get(pos);
- } else {
- // correl not grouped
- throw new AssertionError("Identifier '" + originalRelName + "."
- + originalFieldName + "' is not a group expr");
- }
- }
-
- requiredColumns.set(pos);
- correlNames.add(correlName);
- }
-
- if (correlNames.isEmpty()) {
- // None of the correlating variables originated in this scope.
- return null;
- }
-
- RelNode r = r0;
- if (correlNames.size() > 1) {
- // The same table was referenced more than once.
- // So we deduplicate.
- r = DeduplicateCorrelateVariables.go(rexBuilder, correlNames.get(0),
- Util.skip(correlNames), r0);
- // Add new node to leaves.
- leaves.add(r);
- }
- return new CorrelationUse(correlNames.get(0), requiredColumns.build(), r);
- }
-
- /**
- * Determines whether a sub-query is non-correlated. Note that a
- * non-correlated sub-query can contain correlated references, provided those
- * references do not reference select statements that are parents of the
- * sub-query.
- *
- * @param subq the sub-query
- * @param bb blackboard used while converting the sub-query, i.e., the
- * blackboard of the parent query of this sub-query
- * @return true if the sub-query is non-correlated
- */
- private boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb) {
- Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(subq);
- for (CorrelationId correlName : correlatedVariables) {
- DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
- String originalRelName = lookup.getOriginalRelName();
-
- final SqlNameMatcher nameMatcher =
- lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
- final SqlValidatorScope.ResolvedImpl resolved =
- new SqlValidatorScope.ResolvedImpl();
- lookup.bb.scope.resolve(ImmutableList.of(originalRelName), nameMatcher,
- false, resolved);
-
- SqlValidatorScope ancestorScope = resolved.only().scope;
-
- // If the correlated reference is in a scope that's "above" the
- // sub-query, then this is a correlated sub-query.
- SqlValidatorScope parentScope = bb.scope;
- do {
- if (ancestorScope == parentScope) {
- return false;
- }
- if (parentScope instanceof DelegatingScope) {
- parentScope = ((DelegatingScope) parentScope).getParent();
- } else {
- break;
- }
- } while (parentScope != null);
- }
- return true;
- }
-
- /**
- * Returns a list of fields to be prefixed to each relational expression.
- *
- * @return List of system fields
- */
- protected List<RelDataTypeField> getSystemFields() {
- return Collections.emptyList();
- }
-
- private RexNode convertJoinCondition(Blackboard bb,
- SqlValidatorNamespace leftNamespace,
- SqlValidatorNamespace rightNamespace,
- SqlNode condition,
- JoinConditionType conditionType,
- RelNode leftRel,
- RelNode rightRel) {
- if (condition == null) {
- return rexBuilder.makeLiteral(true);
- }
- bb.setRoot(ImmutableList.of(leftRel, rightRel));
- replaceSubQueries(bb, condition, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
- switch (conditionType) {
- case ON:
- bb.setRoot(ImmutableList.of(leftRel, rightRel));
- return bb.convertExpression(condition);
- case USING:
- final SqlNodeList list = (SqlNodeList) condition;
- final List<String> nameList = new ArrayList<>();
- for (SqlNode columnName : list) {
- final SqlIdentifier id = (SqlIdentifier) columnName;
- String name = id.getSimple();
- nameList.add(name);
- }
- return convertUsing(leftNamespace, rightNamespace, nameList);
- default:
- throw Util.unexpected(conditionType);
- }
- }
-
- /**
- * Returns an expression for matching columns of a USING clause or inferred
- * from NATURAL JOIN. "a JOIN b USING (x, y)" becomes "a.x = b.x AND a.y =
- * b.y". Returns null if the column list is empty.
- *
- * @param leftNamespace Namespace of left input to join
- * @param rightNamespace Namespace of right input to join
- * @param nameList List of column names to join on
- * @return Expression to match columns from name list, or true if name list
- * is empty
- */
- private RexNode convertUsing(SqlValidatorNamespace leftNamespace,
- SqlValidatorNamespace rightNamespace,
- List<String> nameList) {
- final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
- final List<RexNode> list = Lists.newArrayList();
- for (String name : nameList) {
- List<RexNode> operands = new ArrayList<>();
- int offset = 0;
- for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace,
- rightNamespace)) {
- final RelDataType rowType = n.getRowType();
- final RelDataTypeField field = nameMatcher.field(rowType, name);
- operands.add(
- rexBuilder.makeInputRef(field.getType(),
- offset + field.getIndex()));
- offset += rowType.getFieldList().size();
- }
- list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands));
- }
- return RexUtil.composeConjunction(rexBuilder, list, false);
- }
-
- private static JoinRelType convertJoinType(JoinType joinType) {
- switch (joinType) {
- case COMMA:
- case INNER:
- case CROSS:
- return JoinRelType.INNER;
- case FULL:
- return JoinRelType.FULL;
- case LEFT:
- return JoinRelType.LEFT;
- case RIGHT:
- return JoinRelType.RIGHT;
- default:
- throw Util.unexpected(joinType);
- }
- }
-
- /**
- * Converts the SELECT, GROUP BY and HAVING clauses of an aggregate query.
- *
- * <p>This method extracts SELECT, GROUP BY and HAVING clauses, and creates
- * an {@link AggConverter}, then delegates to {@link #createAggImpl}.
- * Derived class may override this method to change any of those clauses or
- * specify a different {@link AggConverter}.
- *
- * @param bb Scope within which to resolve identifiers
- * @param select Query
- * @param orderExprList Additional expressions needed to implement ORDER BY
- */
- protected void convertAgg(
- Blackboard bb,
- SqlSelect select,
- List<SqlNode> orderExprList) {
- assert bb.root != null : "precondition: child != null";
- SqlNodeList groupList = select.getGroup();
- SqlNodeList selectList = select.getSelectList();
- SqlNode having = select.getHaving();
-
- final AggConverter aggConverter = new AggConverter(bb, select);
- createAggImpl(
- bb,
- aggConverter,
- selectList,
- groupList,
- having,
- orderExprList);
- }
-
- protected final void createAggImpl(
- Blackboard bb,
- final AggConverter aggConverter,
- SqlNodeList selectList,
- SqlNodeList groupList,
- SqlNode having,
- List<SqlNode> orderExprList) {
- // Find aggregate functions in SELECT and HAVING clause
- final AggregateFinder aggregateFinder = new AggregateFinder();
- selectList.accept(aggregateFinder);
- if (having != null) {
- having.accept(aggregateFinder);
- }
-
- // first replace the sub-queries inside the aggregates
- // because they will provide input rows to the aggregates.
- replaceSubQueries(bb, aggregateFinder.list,
- RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-
- // If group-by clause is missing, pretend that it has zero elements.
- if (groupList == null) {
- groupList = SqlNodeList.EMPTY;
- }
-
- replaceSubQueries(bb, groupList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-
- // register the group exprs
-
- // build a map to remember the projections from the top scope to the
- // output of the current root.
- //
- // Calcite allows expressions, not just column references in
- // group by list. This is not SQL 2003 compliant, but hey.
-
- final AggregatingSelectScope scope = aggConverter.aggregatingSelectScope;
- final AggregatingSelectScope.Resolved r = scope.resolved.get();
- for (SqlNode groupExpr : r.groupExprList) {
- aggConverter.addGroupExpr(groupExpr);
- }
-
- RexNode havingExpr = null;
- final List<Pair<RexNode, String>> projects = Lists.newArrayList();
-
- try {
- Preconditions.checkArgument(bb.agg == null, "already in agg mode");
- bb.agg = aggConverter;
-
- // convert the select and having expressions, so that the
- // agg converter knows which aggregations are required
-
- selectList.accept(aggConverter);
- // Assert we don't have dangling items left in the stack
- assert !aggConverter.inOver;
- for (SqlNode expr : orderExprList) {
- expr.accept(aggConverter);
- assert !aggConverter.inOver;
- }
- if (having != null) {
- having.accept(aggConverter);
- assert !aggConverter.inOver;
- }
-
- // compute inputs to the aggregator
- List<Pair<RexNode, String>> preExprs = aggConverter.getPreExprs();
-
- if (preExprs.size() == 0) {
- // Special case for COUNT(*), where we can end up with no inputs
- // at all. The rest of the system doesn't like 0-tuples, so we
- // select a dummy constant here.
- final RexNode zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
- preExprs = ImmutableList.of(Pair.of(zero, (String) null));
- }
-
- final RelNode inputRel = bb.root;
-
- // Project the expressions required by agg and having.
- bb.setRoot(
- RelOptUtil.createProject(
- inputRel,
- preExprs,
- true),
- false);
- bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
-
- // REVIEW jvs 31-Oct-2007: doesn't the declaration of
- // monotonicity here assume sort-based aggregation at
- // the physical level?
-
- // Tell bb which of group columns are sorted.
- bb.columnMonotonicities.clear();
- for (SqlNode groupItem : groupList) {
- bb.columnMonotonicities.add(
- bb.scope.getMonotonicity(groupItem));
- }
-
- // Add the aggregator
- bb.setRoot(
- createAggregate(bb, r.indicator, r.groupSet, r.groupSets,
- aggConverter.getAggCalls()),
- false);
-
- // Generate NULL values for rolled-up not-null fields.
- final Aggregate aggregate = (Aggregate) bb.root;
- if (aggregate.getGroupType() != Aggregate.Group.SIMPLE) {
- assert aggregate.indicator;
- List<Pair<RexNode, String>> projects2 = Lists.newArrayList();
- int converted = 0;
- final int groupCount = aggregate.getGroupSet().cardinality();
- for (RelDataTypeField field : aggregate.getRowType().getFieldList()) {
- final int i = field.getIndex();
- final RexNode rex;
- if (i < groupCount && r.isNullable(i)) {
- ++converted;
-
- rex = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
- rexBuilder.makeInputRef(aggregate, groupCount + i),
- rexBuilder.makeCast(
- typeFactory.createTypeWithNullability(
- field.getType(), true),
- rexBuilder.constantNull()),
- rexBuilder.makeInputRef(aggregate, i));
- } else {
- rex = rexBuilder.makeInputRef(aggregate, i);
- }
- projects2.add(Pair.of(rex, field.getName()));
- }
- if (converted > 0) {
- bb.setRoot(
- RelOptUtil.createProject(bb.root, projects2, true),
- false);
- }
- }
-
- bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
-
- // Replace sub-queries in having here and modify having to use
- // the replaced expressions
- if (having != null) {
- SqlNode newHaving = pushDownNotForIn(bb.scope, having);
- replaceSubQueries(bb, newHaving, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
- havingExpr = bb.convertExpression(newHaving);
- if (havingExpr.isAlwaysTrue()) {
- havingExpr = null;
- }
- }
-
- // Now convert the other sub-queries in the select list.
- // This needs to be done separately from the sub-query inside
- // any aggregate in the select list, and after the aggregate rel
- // is allocated.
- replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-
- // Now sub-queries in the entire select list have been converted.
- // Convert the select expressions to get the final list to be
- // projected.
- int k = 0;
-
- // For select expressions, use the field names previously assigned
- // by the validator. If we derive afresh, we might generate names
- // like "EXPR$2" that don't match the names generated by the
- // validator. This is especially the case when there are system
- // fields; system fields appear in the relnode's rowtype but do not
- // (yet) appear in the validator type.
- final SelectScope selectScope =
- SqlValidatorUtil.getEnclosingSelectScope(bb.scope);
- assert selectScope != null;
- final SqlValidatorNamespace selectNamespace =
- validator.getNamespace(selectScope.getNode());
- final List<String> names =
- selectNamespace.getRowType().getFieldNames();
- int sysFieldCount = selectList.size() - names.size();
- for (SqlNode expr : selectList) {
- projects.add(
- Pair.of(bb.convertExpression(expr),
- k < sysFieldCount
- ? validator.deriveAlias(expr, k++)
- : names.get(k++ - sysFieldCount)));
- }
-
- for (SqlNode expr : orderExprList) {
- projects.add(
- Pair.of(bb.convertExpression(expr),
- validator.deriveAlias(expr, k++)));
- }
- } finally {
- bb.agg = null;
- }
-
- // implement HAVING (we have already checked that it is non-trivial)
- if (havingExpr != null) {
- final RelFactories.FilterFactory factory =
- RelFactories.DEFAULT_FILTER_FACTORY;
- bb.setRoot(factory.createFilter(bb.root, havingExpr), false);
- }
-
- // implement the SELECT list
- bb.setRoot(
- RelOptUtil.createProject(
- bb.root,
- projects,
- true),
- false);
-
- // Tell bb which of group columns are sorted.
- bb.columnMonotonicities.clear();
- for (SqlNode selectItem : selectList) {
- bb.columnMonotonicities.add(
- bb.scope.getMonotonicity(selectItem));
- }
- }
-
- /**
- * Creates an Aggregate.
- *
- * <p>In case the aggregate rel changes the order in which it projects
- * fields, the <code>groupExprProjection</code> parameter is provided, and
- * the implementation of this method may modify it.
- *
- * <p>The <code>sortedCount</code> parameter is the number of expressions
- * known to be monotonic. These expressions must be on the leading edge of
- * the grouping keys. The default implementation of this method ignores this
- * parameter.
- *
- * @param bb Blackboard
- * @param indicator Whether to output fields indicating grouping sets
- * @param groupSet Bit set of ordinals of grouping columns
- * @param groupSets Grouping sets
- * @param aggCalls Array of calls to aggregate functions
- * @return LogicalAggregate
- */
- protected RelNode createAggregate(Blackboard bb, boolean indicator,
- ImmutableBitSet groupSet, ImmutableList<ImmutableBitSet> groupSets,
- List<AggregateCall> aggCalls) {
- return LogicalAggregate.create(
- bb.root, indicator, groupSet, groupSets, aggCalls);
- }
-
- public RexDynamicParam convertDynamicParam(
- final SqlDynamicParam dynamicParam) {
- // REVIEW jvs 8-Jan-2005: dynamic params may be encountered out of
- // order. Should probably cross-check with the count from the parser
- // at the end and make sure they all got filled in. Why doesn't List
- // have a resize() method?!? Make this a utility.
- while (dynamicParam.getIndex() >= dynamicParamSqlNodes.size()) {
- dynamicParamSqlNodes.add(null);
- }
-
- dynamicParamSqlNodes.set(
- dynamicParam.getIndex(),
- dynamicParam);
- return rexBuilder.makeDynamicParam(
- getDynamicParamType(dynamicParam.getIndex()),
- dynamicParam.getIndex());
- }
-
- /**
- * Creates a list of collations required to implement the ORDER BY clause,
- * if there is one. Populates <code>extraOrderExprs</code> with any sort
- * expressions which are not in the select clause.
- *
- * @param bb Scope within which to resolve identifiers
- * @param select Select clause. Never null, because we invent a
- * dummy SELECT if ORDER BY is applied to a set
- * operation (UNION etc.)
- * @param orderList Order by clause, may be null
- * @param extraOrderExprs Sort expressions which are not in the select
- * clause (output)
- * @param collationList List of collations (output)
- */
- protected void gatherOrderExprs(
- Blackboard bb,
- SqlSelect select,
- SqlNodeList orderList,
- List<SqlNode> extraOrderExprs,
- List<RelFieldCollation> collationList) {
- // TODO: add validation rules to SqlValidator also
- assert bb.root != null : "precondition: child != null";
- assert select != null;
- if (orderList == null) {
- return;
- }
- for (SqlNode orderItem : orderList) {
- collationList.add(
- convertOrderItem(
- select,
- orderItem,
- extraOrderExprs,
- RelFieldCollation.Direction.ASCENDING,
- RelFieldCollation.NullDirection.UNSPECIFIED));
- }
- }
-
- protected RelFieldCollation convertOrderItem(
- SqlSelect select,
- SqlNode orderItem, List<SqlNode> extraExprs,
- RelFieldCollation.Direction direction,
- RelFieldCollation.NullDirection nullDirection) {
- assert select != null;
- // Handle DESC keyword, e.g. 'select a, b from t order by a desc'.
- switch (orderItem.getKind()) {
- case DESCENDING:
- return convertOrderItem(
- select,
- ((SqlCall) orderItem).operand(0),
- extraExprs,
- RelFieldCollation.Direction.DESCENDING,
- nullDirection);
- case NULLS_FIRST:
- return convertOrderItem(
- select,
- ((SqlCall) orderItem).operand(0),
- extraExprs,
- direction,
- RelFieldCollation.NullDirection.FIRST);
- case NULLS_LAST:
- return convertOrderItem(
- select,
- ((SqlCall) orderItem).operand(0),
- extraExprs,
- direction,
- RelFieldCollation.NullDirection.LAST);
- }
-
- SqlNode converted = validator.expandOrderExpr(select, orderItem);
-
- switch (nullDirection) {
- case UNSPECIFIED:
- nullDirection = validator.getDefaultNullCollation().last(desc(direction))
- ? RelFieldCollation.NullDirection.LAST
- : RelFieldCollation.NullDirection.FIRST;
- }
-
- // Scan the select list and order exprs for an identical expression.
- final SelectScope selectScope = validator.getRawSelectScope(select);
- int ordinal = -1;
- for (SqlNode selectItem : selectScope.getExpandedSelectList()) {
- ++ordinal;
- if (converted.equalsDeep(stripAs(selectItem), Litmus.IGNORE)) {
- return new RelFieldCollation(ordinal, direction, nullDirection);
- }
- }
-
- for (SqlNode extraExpr : extraExprs) {
- ++ordinal;
- if (converted.equalsDeep(extraExpr, Litmus.IGNORE)) {
- return new RelFieldCollation(ordinal, direction, nullDirection);
- }
- }
-
- // TODO: handle collation sequence
- // TODO: flag expressions as non-standard
-
- extraExprs.add(converted);
- return new RelFieldCollation(ordinal + 1, direction, nullDirection);
- }
-
- private static boolean desc(RelFieldCollation.Direction direction) {
- switch (direction) {
- case DESCENDING:
- case STRICTLY_DESCENDING:
- return true;
- default:
- return false;
- }
- }
-
- @Deprecated // to be removed before 2.0
- protected boolean enableDecorrelation() {
- // disable sub-query decorrelation when needed.
- // e.g. if outer joins are not supported.
- return config.isDecorrelationEnabled();
- }
-
- protected RelNode decorrelateQuery(RelNode rootRel) {
- return RelDecorrelator.decorrelateQuery(rootRel);
- }
-
- /**
- * Returns whether to trim unused fields as part of the conversion process.
- *
- * @return Whether to trim unused fields
- */
- @Deprecated // to be removed before 2.0
- public boolean isTrimUnusedFields() {
-// return config.isTrimUnusedFields();
- /* OVERRIDE POINT */
- return false;
- }
-
- /**
- * Recursively converts a query to a relational expression.
- *
- * @param query Query
- * @param top Whether this query is the top-level query of the
- * statement
- * @param targetRowType Target row type, or null
- * @return Relational expression
- */
- protected RelRoot convertQueryRecursive(SqlNode query, boolean top,
- RelDataType targetRowType) {
- final SqlKind kind = query.getKind();
- switch (kind) {
- case SELECT:
- return RelRoot.of(convertSelect((SqlSelect) query, top), kind);
- case INSERT:
- return RelRoot.of(convertInsert((SqlInsert) query), kind);
- case DELETE:
- return RelRoot.of(convertDelete((SqlDelete) query), kind);
- case UPDATE:
- return RelRoot.of(convertUpdate((SqlUpdate) query), kind);
- case MERGE:
- return RelRoot.of(convertMerge((SqlMerge) query), kind);
- case UNION:
- case INTERSECT:
- case EXCEPT:
- return RelRoot.of(convertSetOp((SqlCall) query), kind);
- case WITH:
- return convertWith((SqlWith) query, top);
- case VALUES:
- return RelRoot.of(convertValues((SqlCall) query, targetRowType), kind);
- default:
- throw new AssertionError("not a query: " + query);
- }
- }
-
- /**
- * Converts a set operation (UNION, INTERSECT, MINUS) into relational
- * expressions.
- *
- * @param call Call to set operator
- * @return Relational expression
- */
- protected RelNode convertSetOp(SqlCall call) {
- final RelNode left =
- convertQueryRecursive(call.operand(0), false, null).project();
- final RelNode right =
- convertQueryRecursive(call.operand(1), false, null).project();
- switch (call.getKind()) {
- case UNION:
- return LogicalUnion.create(ImmutableList.of(left, right), all(call));
-
- case INTERSECT:
- return LogicalIntersect.create(ImmutableList.of(left, right), all(call));
-
- case EXCEPT:
- return LogicalMinus.create(ImmutableList.of(left, right), all(call));
-
- default:
- throw Util.unexpected(call.getKind());
- }
- }
-
- private boolean all(SqlCall call) {
- return ((SqlSetOperator) call.getOperator()).isAll();
- }
-
- protected RelNode convertInsert(SqlInsert call) {
- RelOptTable targetTable = getTargetTable(call);
-
- final RelDataType targetRowType =
- validator.getValidatedNodeType(call);
- assert targetRowType != null;
- RelNode sourceRel =
- convertQueryRecursive(call.getSource(), false, targetRowType).project();
- RelNode massagedRel = convertColumnList(call, sourceRel);
-
- return createModify(targetTable, massagedRel);
- }
-
- /** Creates a relational expression to modify a table or modifiable view. */
- private RelNode createModify(RelOptTable targetTable, RelNode source) {
- final ModifiableTable modifiableTable =
- targetTable.unwrap(ModifiableTable.class);
- if (modifiableTable != null) {
- return modifiableTable.toModificationRel(cluster, targetTable,
- catalogReader, source, LogicalTableModify.Operation.INSERT, null,
- null, false);
- }
- final ModifiableView modifiableView =
- targetTable.unwrap(ModifiableView.class);
- if (modifiableView != null) {
- final Table delegateTable = modifiableView.getTable();
- final RelDataType delegateRowType = delegateTable.getRowType(typeFactory);
- final RelOptTable delegateRelOptTable =
- RelOptTableImpl.create(null, delegateRowType, delegateTable,
- modifiableView.getTablePath());
- final RelNode newSource =
- createSource(targetTable, source, modifiableView, delegateRowType);
- return createModify(delegateRelOptTable, newSource);
- }
- return LogicalTableModify.create(targetTable, catalogReader, source,
- LogicalTableModify.Operation.INSERT, null, null, false);
- }
-
- /** Wraps a relational expression in the projects and filters implied by
- * a {@link ModifiableView}.
- *
- * <p>The input relational expression is suitable for inserting into the view,
- * and the returned relational expression is suitable for inserting into its
- * delegate table.
- *
- * <p>In principle, the delegate table of a view might be another modifiable
- * view, and if so, the process can be repeated. */
- private RelNode createSource(RelOptTable targetTable, RelNode source,
- ModifiableView modifiableView, RelDataType delegateRowType) {
- final ImmutableIntList mapping = modifiableView.getColumnMapping();
- assert mapping.size() == targetTable.getRowType().getFieldCount();
-
- // For columns represented in the mapping, the expression is just a field
- // reference.
- final Map<Integer, RexNode> projectMap = new HashMap<>();
- final List<RexNode> filters = new ArrayList<>();
- for (int i = 0; i < mapping.size(); i++) {
- int target = mapping.get(i);
- if (target >= 0) {
- projectMap.put(target, RexInputRef.of(i, source.getRowType()));
- }
- }
-
- // For columns that are not in the mapping, and have a constraint of the
- // form "column = value", the expression is the literal "value".
- //
- // If a column has multiple constraints, the extra ones will become a
- // filter.
- final RexNode constraint =
- modifiableView.getConstraint(rexBuilder, delegateRowType);
- RelOptUtil.inferViewPredicates(projectMap, filters, constraint);
- final List<Pair<RexNode, String>> projects = new ArrayList<>();
- for (RelDataTypeField field : delegateRowType.getFieldList()) {
- RexNode node = projectMap.get(field.getIndex());
- if (node == null) {
- node = rexBuilder.makeNullLiteral(field.getType());
- }
- projects.add(
- Pair.of(rexBuilder.ensureType(field.getType(), node, false),
- field.getName()));
- }
-
- source = RelOptUtil.createProject(source, projects, true);
- if (filters.size() > 0) {
- source = RelOptUtil.createFilter(source, filters);
- }
- return source;
- }
-
- private RelOptTable.ToRelContext createToRelContext() {
- return new RelOptTable.ToRelContext() {
- public RelOptCluster getCluster() {
- return cluster;
- }
-
- @Override public RelRoot expandView(
- RelDataType rowType,
- String queryString,
- List<String> schemaPath,
- List<String> viewPath) {
- return viewExpander.expandView(rowType, queryString, schemaPath, viewPath);
- }
-
- };
- }
-
- public RelNode toRel(RelOptTable table) {
- return table.toRel(createToRelContext());
- }
-
- protected RelOptTable getTargetTable(SqlNode call) {
- final SqlValidatorNamespace targetNs = validator.getNamespace(call);
- if (targetNs.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) {
- final SqlValidatorImpl.DmlNamespace dmlNamespace =
- targetNs.unwrap(SqlValidatorImpl.DmlNamespace.class);
- return SqlValidatorUtil.getRelOptTable(dmlNamespace, catalogReader, null, null);
- }
- final SqlValidatorNamespace resolvedNamespace = targetNs.resolve();
- return SqlValidatorUtil.getRelOptTable(resolvedNamespace, catalogReader, null, null);
- }
-
- /**
- * Creates a source for an INSERT statement.
- *
- * <p>If the column list is not specified, source expressions match target
- * columns in order.
- *
- * <p>If the column list is specified, Source expressions are mapped to
- * target columns by name via targetColumnList, and may not cover the entire
- * target table. So, we'll make up a full row, using a combination of
- * default values and the source expressions provided.
- *
- * @param call Insert expression
- * @param sourceRel Source relational expression
- * @return Converted INSERT statement
- */
- protected RelNode convertColumnList(
- SqlInsert call,
- RelNode sourceRel) {
- RelDataType sourceRowType = sourceRel.getRowType();
- final RexNode sourceRef =
- rexBuilder.makeRangeReference(sourceRowType, 0, false);
- final List<String> targetColumnNames = new ArrayList<>();
- final List<RexNode> columnExprs = new ArrayList<>();
- collectInsertTargets(call, sourceRef, targetColumnNames, columnExprs);
-
- final RelOptTable targetTable = getTargetTable(call);
- final RelDataType targetRowType = targetTable.getRowType();
- final List<RelDataTypeField> targetFields =
- targetRowType.getFieldList();
- final List<RexNode> sourceExps =
- new ArrayList<>(
- Collections.<RexNode>nCopies(targetFields.size(), null));
- final List<String> fieldNames =
- new ArrayList<>(
- Collections.<String>nCopies(targetFields.size(), null));
-
- final InitializerExpressionFactory initializerFactory =
- getInitializerFactory(validator.getNamespace(call).getTable());
-
- // Walk the name list and place the associated value in the
- // expression list according to the ordinal value returned from
- // the table construct, leaving nulls in the list for columns
- // that are not referenced.
- final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
- for (Pair<String, RexNode> p : Pair.zip(targetColumnNames, columnExprs)) {
- RelDataTypeField field = nameMatcher.field(targetRowType, p.left);
- assert field != null : "column " + p.left + " not found";
- sourceExps.set(field.getIndex(), p.right);
- }
-
- // Walk the expression list and get default values for any columns
- // that were not supplied in the statement. Get field names too.
- for (int i = 0; i < targetFields.size(); ++i) {
- final RelDataTypeField field = targetFields.get(i);
- final String fieldName = field.getName();
- fieldNames.set(i, fieldName);
- if (sourceExps.get(i) != null) {
- if (initializerFactory.isGeneratedAlways(targetTable, i)) {
- throw RESOURCE.insertIntoAlwaysGenerated(fieldName).ex();
- }
- continue;
- }
- sourceExps.set(i,
- initializerFactory.newColumnDefaultValue(targetTable, i,
- new InitializerContext() {
- public RexBuilder getRexBuilder() {
- return rexBuilder;
- }
- }));
-
- // bare nulls are dangerous in the wrong hands
- sourceExps.set(i,
- castNullLiteralIfNeeded(sourceExps.get(i), field.getType()));
- }
-
- return RelOptUtil.createProject(sourceRel, sourceExps, fieldNames, true);
- }
-
- private InitializerExpressionFactory getInitializerFactory(
- SqlValidatorTable validatorTable) {
- // We might unwrap a null instead of a InitializerExpressionFactory.
- final Table table = unwrap(validatorTable, Table.class);
- if (table != null) {
- InitializerExpressionFactory f =
- unwrap(table, InitializerExpressionFactory.class);
- if (f != null) {
- return f;
- }
- }
- return new NullInitializerExpressionFactory();
- }
-
- private static <T> T unwrap(Object o, Class<T> clazz) {
- if (o instanceof Wrapper) {
- return ((Wrapper) o).unwrap(clazz);
- }
- return null;
- }
-
- private RexNode castNullLiteralIfNeeded(RexNode node, RelDataType type) {
- if (!RexLiteral.isNullLiteral(node)) {
- return node;
- }
- return rexBuilder.makeCast(type, node);
- }
-
- /**
- * Given an INSERT statement, collects the list of names to be populated and
- * the expressions to put in them.
- *
- * @param call Insert statement
- * @param sourceRef Expression representing a row from the source
- * relational expression
- * @param targetColumnNames List of target column names, to be populated
- * @param columnExprs List of expressions, to be populated
- */
- protected void collectInsertTargets(
- SqlInsert call,
- final RexNode sourceRef,
- final List<String> targetColumnNames,
- List<RexNode> columnExprs) {
- final RelOptTable targetTable = getTargetTable(call);
- final RelDataType tableRowType = targetTable.getRowType();
- SqlNodeList targetColumnList = call.getTargetColumnList();
... 2953 lines suppressed ...