Skip to content

Commit

Permalink
[CALCITE-6482] OracleSqlDialect support bool literal as predicate
Browse files Browse the repository at this point in the history
  • Loading branch information
suibianwanwank committed Jul 17, 2024
1 parent ace3afe commit fd6d492
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 2 deletions.
54 changes: 54 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlBoolLiteral.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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;

import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;

import org.checkerframework.checker.nullness.qual.Nullable;


/**
* A SQL literal representing a BOOLEAN value,
* for example <code>BOOLEAN 'TRUE'</code>.
*
* <p>Create values using {@link SqlLiteral#createBoolean}.
*/
public class SqlBoolLiteral extends SqlLiteral{

/**
* Creates a <code>SqlBoolLiteral</code>.
*
* @param value
* @param typeName
* @param pos
*/
SqlBoolLiteral(@Nullable Boolean value, SqlTypeName typeName, SqlParserPos pos) {
super(value, typeName, pos);
}

@Override
public SqlLiteral clone(SqlParserPos pos) {
return new SqlBoolLiteral(value == null ? null : (Boolean) value, getTypeName(), pos);
}

@Override
public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
writer.getDialect().unparseBoolLiteral(writer, this , leftPrec , rightPrec);
}
}
6 changes: 6 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,12 @@ public void unparseCall(SqlWriter writer, SqlCall call, int leftPrec,
}
}

public void unparseBoolLiteral(SqlWriter writer,
SqlBoolLiteral literal,int leftPrec, int rightPrec) {
writer.keyword(
literal.getValue() == null ? "UNKNOWN" : (Boolean) literal.getValue() ? "TRUE" : "FALSE");

Check failure on line 472 in core/src/main/java/org/apache/calcite/sql/SqlDialect.java

View workflow job for this annotation

GitHub Actions / CheckerFramework (JDK 11), oldest Guava

[Task :core:compileJava] [condition.nullable] condition on a possibly-null value (Boolean)literal.getValue() literal.getValue() == null ? "UNKNOWN" : (Boolean) literal.getValue() ? "TRUE" : "FALSE"); ^

Check failure on line 472 in core/src/main/java/org/apache/calcite/sql/SqlDialect.java

View workflow job for this annotation

GitHub Actions / CheckerFramework (JDK 11)

[Task :core:compileJava] [condition.nullable] condition on a possibly-null value (Boolean)literal.getValue() literal.getValue() == null ? "UNKNOWN" : (Boolean) literal.getValue() ? "TRUE" : "FALSE"); ^
}

public void unparseDateTimeLiteral(SqlWriter writer,
SqlAbstractDateTimeLiteral literal, int leftPrec, int rightPrec) {
writer.literal(literal.toString());
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,8 @@ public static SqlLiteral createNull(SqlParserPos pos) {
public static SqlLiteral createBoolean(
boolean b,
SqlParserPos pos) {
return b ? new SqlLiteral(Boolean.TRUE, SqlTypeName.BOOLEAN, pos)
: new SqlLiteral(Boolean.FALSE, SqlTypeName.BOOLEAN, pos);
return b ? new SqlBoolLiteral(Boolean.TRUE, SqlTypeName.BOOLEAN, pos)
: new SqlBoolLiteral(Boolean.FALSE, SqlTypeName.BOOLEAN, pos);
}

public static SqlLiteral createUnknown(SqlParserPos pos) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
import org.apache.calcite.sql.SqlAbstractDateTimeLiteral;
import org.apache.calcite.sql.SqlAlienSystemTypeNameSpec;
import org.apache.calcite.sql.SqlBoolLiteral;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlDataTypeSpec;
import org.apache.calcite.sql.SqlDateLiteral;
import org.apache.calcite.sql.SqlDialect;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNumericLiteral;
import org.apache.calcite.sql.SqlTimeLiteral;
import org.apache.calcite.sql.SqlTimestampLiteral;
import org.apache.calcite.sql.SqlUtil;
Expand All @@ -44,6 +46,8 @@

import java.util.List;

import static org.apache.calcite.rel.rel2sql.SqlImplementor.POS;

/**
* A <code>SqlDialect</code> implementation for the Oracle database.
*/
Expand All @@ -69,6 +73,15 @@ public class OracleSqlDialect extends SqlDialect {

public static final SqlDialect DEFAULT = new OracleSqlDialect(DEFAULT_CONTEXT);


/** SQL numeric literal {@code 0}. */
static final SqlNumericLiteral ZERO =
SqlNumericLiteral.createExactNumeric("0", POS);

/** SQL numeric literal {@code 1}. */
static final SqlNumericLiteral ONE =
SqlLiteral.createExactNumeric("1", POS);

private final int majorVersion;

/** Creates an OracleSqlDialect. */
Expand Down Expand Up @@ -126,6 +139,20 @@ public OracleSqlDialect(Context context) {
return false;
}

@Override
public void unparseBoolLiteral(SqlWriter writer,
SqlBoolLiteral literal, int leftPrec, int rightPrec) {
Boolean value = (Boolean) literal.getValue();
if (value == null || majorVersion >= 23) {
super.unparseBoolLiteral(writer, literal, leftPrec, rightPrec);
return;
}
// low version oracle not support bool literal
SqlCall call = SqlStdOperatorTable.EQUALS.createCall(
SqlParserPos.ZERO, ONE, Boolean.TRUE.equals(value) ? ONE : ZERO);
super.unparseCall(writer, call, leftPrec, rightPrec);
}

@Override public void unparseDateTimeLiteral(SqlWriter writer,
SqlAbstractDateTimeLiteral literal, int leftPrec, int rightPrec) {
if (literal instanceof SqlTimestampLiteral) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7700,6 +7700,28 @@ private void checkLiteral2(String expression, String expected) {
.withOracle(11).throws_("Lower Oracle version(<12) doesn't support offset/fetch syntax!");
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5723">[CALCITE-5723]
* Oracle dialect generates SQL that cannot be recognized by lower version
* Oracle Server(<12) when unparsing OffsetFetch</a>. */
@Test void testBoolLiteralOracle() {
String query = "SELECT \"e1\".\"department_id\" "
+ "FROM \"employee\" \"e1\""
+ "LEFT JOIN \"employee\" \"e2\""
+ "ON TRUE";
String expectedVersionLow = "SELECT \"employee\".\"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "LEFT JOIN \"foodmart\".\"employee\" \"employee0\" "
+ "ON 1 = 1";
String expectedVersionHigh = "SELECT \"employee\".\"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "LEFT JOIN \"foodmart\".\"employee\" \"employee0\" "
+ "ON TRUE";
sql(query)
.withOracle(23).ok(expectedVersionHigh)
.withOracle(11).ok(expectedVersionLow);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5265">[CALCITE-5265]
* JDBC adapter sometimes adds unnecessary parentheses around SELECT in INSERT</a>. */
Expand Down

0 comments on commit fd6d492

Please sign in to comment.