@Test public void testExplainAsXml() { String sql = "select 1 + 2, 3 from (values (true))"; final RelNode rel = tester.convertSqlToRel(sql).rel; StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); RelXmlWriter planWriter = new RelXmlWriter(pw, SqlExplainLevel.EXPPLAN_ATTRIBUTES); rel.explain(planWriter); pw.flush(); TestUtil.assertEqualsVerbose( "<RelNode type=\"LogicalProject\">\n" + "\t<Property name=\"EXPR$0\">\n" + "\t\t+(1, 2)\t</Property>\n" + "\t<Property name=\"EXPR$1\">\n" + "\t\t3\t</Property>\n" + "\t<Inputs>\n" + "\t\t<RelNode type=\"LogicalValues\">\n" + "\t\t\t<Property name=\"tuples\">\n" + "\t\t\t\t[{ true }]\t\t\t</Property>\n" + "\t\t\t<Inputs/>\n" + "\t\t</RelNode>\n" + "\t</Inputs>\n" + "</RelNode>\n", Util.toLinux(sw.toString())); }
/** Add the Filter condition to the pulledPredicates list from the input. */ public RelOptPredicateList getPredicates(Filter filter, RelMetadataQuery mq) { final RelNode input = filter.getInput(); final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input); return Util.first(inputInfo, RelOptPredicateList.EMPTY) .union(RelOptPredicateList.of(RelOptUtil.conjunctions(filter.getCondition()))); }
public void unparse(SqlWriter writer, int leftPrec, int rightPrec) { switch (typeName) { case BOOLEAN: writer.keyword(value == null ? "UNKNOWN" : (Boolean) value ? "TRUE" : "FALSE"); break; case NULL: writer.keyword("NULL"); break; case CHAR: case DECIMAL: case DOUBLE: case BINARY: // should be handled in subtype throw Util.unexpected(typeName); case SYMBOL: if (value instanceof Enum) { Enum enumVal = (Enum) value; writer.keyword(enumVal.toString()); } else { writer.keyword(String.valueOf(value)); } break; default: writer.literal(value.toString()); } }
/** @return whether value is appropriate for its type (we have rules about these things) */ public static boolean valueMatchesType(Object value, SqlTypeName typeName) { switch (typeName) { case BOOLEAN: return (value == null) || (value instanceof Boolean); case NULL: return value == null; case DECIMAL: case DOUBLE: return value instanceof BigDecimal; case DATE: case TIME: case TIMESTAMP: return value instanceof Calendar; case INTERVAL_DAY_TIME: case INTERVAL_YEAR_MONTH: return value instanceof SqlIntervalLiteral.IntervalValue; case BINARY: return value instanceof BitString; case CHAR: return value instanceof NlsString; case SYMBOL: return (value instanceof SqlSymbol) || (value instanceof SqlSampleSpec) || (value instanceof TimeUnitRange); case MULTISET: return true; case INTEGER: // not allowed -- use Decimal case VARCHAR: // not allowed -- use Char case VARBINARY: // not allowed -- use Binary default: throw Util.unexpected(typeName); } }
private static Comparable zeroValue(RelDataType type) { switch (type.getSqlTypeName()) { case CHAR: return new NlsString(Spaces.of(type.getPrecision()), null, null); case VARCHAR: return new NlsString("", null, null); case BINARY: return new ByteString(new byte[type.getPrecision()]); case VARBINARY: return ByteString.EMPTY; case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case DECIMAL: case FLOAT: case REAL: case DOUBLE: return BigDecimal.ZERO; case BOOLEAN: return false; case TIME: case DATE: case TIMESTAMP: return DateTimeUtils.ZERO_CALENDAR; default: throw Util.unexpected(type.getSqlTypeName()); } }
@Override public String visitLiteral(RexLiteral rexLiteral) { Object v = rexLiteral.getValue(); RelDataType ty = rexLiteral.getType(); switch (rexLiteral.getTypeName()) { case BOOLEAN: return v.toString(); case CHAR: return CompilerUtil.escapeJavaString(((NlsString) v).getValue(), true); case NULL: return "((" + ((Class<?>) typeFactory.getJavaClass(ty)).getCanonicalName() + ")null)"; case DOUBLE: case BIGINT: case DECIMAL: switch (ty.getSqlTypeName()) { case TINYINT: case SMALLINT: case INTEGER: return Long.toString(((BigDecimal) v).longValueExact()); case BIGINT: return Long.toString(((BigDecimal) v).longValueExact()) + 'L'; case DECIMAL: case FLOAT: case REAL: case DOUBLE: return Util.toScientificNotation((BigDecimal) v); } break; default: throw new UnsupportedOperationException(); } return null; }
/** * Creates an expression accessing a given named field from a record. * * <p>NOTE: Be careful choosing the value of {@code caseSensitive}. If the field name was supplied * by an end-user (e.g. as a column alias in SQL), use your session's case-sensitivity setting. * Only hard-code {@code true} if you are sure that the field name is internally generated. * Hard-coding {@code false} is almost certainly wrong. * * @param expr Expression yielding a record * @param fieldName Name of field in record * @param caseSensitive Whether match is case-sensitive * @return Expression accessing a given named field */ public RexNode makeFieldAccess(RexNode expr, String fieldName, boolean caseSensitive) { final RelDataType type = expr.getType(); final RelDataTypeField field = type.getField(fieldName, caseSensitive, false); if (field == null) { throw Util.newInternal("Type '" + type + "' has no field '" + fieldName + "'"); } return makeFieldAccessInternal(expr, field); }
/** * Creates an expression accessing a field with a given ordinal from a record. * * @param expr Expression yielding a record * @param i Ordinal of field * @return Expression accessing given field */ public RexNode makeFieldAccess(RexNode expr, int i) { final RelDataType type = expr.getType(); final List<RelDataTypeField> fields = type.getFieldList(); if ((i < 0) || (i >= fields.size())) { throw Util.newInternal("Field ordinal " + i + " is invalid for " + " type '" + type + "'"); } return makeFieldAccessInternal(expr, fields.get(i)); }
public static void getSchemaObjectMonikers( SqlValidatorCatalogReader catalogReader, List<String> names, List<SqlMoniker> hints) { // Assume that the last name is 'dummy' or similar. List<String> subNames = Util.skipLast(names); // Try successively with catalog.schema, catalog and no prefix List<String> x = catalogReader.getSchemaName(); for (; ; ) { final List<String> names2 = ImmutableList.<String>builder().addAll(x).addAll(subNames).build(); hints.addAll(catalogReader.getAllSchemaObjectNames(names2)); if (x.isEmpty()) { break; } x = Util.skipLast(x); } }
/** Returns a numeric literal's value as a {@link BigDecimal}. */ public BigDecimal bigDecimalValue() { switch (typeName) { case DECIMAL: case DOUBLE: return (BigDecimal) value; default: throw Util.unexpected(typeName); } }
/** * Converts a chained string literals into regular literals; returns regular literals unchanged. */ public static SqlLiteral unchain(SqlNode node) { if (node instanceof SqlLiteral) { return (SqlLiteral) node; } else if (SqlUtil.isLiteralChain(node)) { return SqlLiteralChainOperator.concatenateOperands((SqlCall) node); } else { throw Util.newInternal("invalid literal: " + node); } }
protected RelDataType validateImpl() { final RelDataTypeFactory.FieldInfoBuilder builder = validator.getTypeFactory().builder(); for (SqlMoniker moniker : validator.catalogReader.getAllSchemaObjectNames(names)) { final List<String> names1 = moniker.getFullyQualifiedNames(); final SqlValidatorTable table = validator.catalogReader.getTable(names1); builder.add(Util.last(names1), table.getRowType()); } return builder.build(); }
@Deprecated // to be removed before 2.0 public JdbcProject( RelOptCluster cluster, RelTraitSet traitSet, RelNode input, List<RexNode> projects, RelDataType rowType, int flags) { this(cluster, traitSet, input, projects, rowType); Util.discard(flags); }
/** Creates a call to a windowed agg. */ public RexNode makeOver( RelDataType type, SqlAggFunction operator, List<RexNode> exprs, List<RexNode> partitionKeys, ImmutableList<RexFieldCollation> orderKeys, RexWindowBound lowerBound, RexWindowBound upperBound, boolean physical, boolean allowPartial, boolean nullWhenCountZero) { assert operator != null; assert exprs != null; assert partitionKeys != null; assert orderKeys != null; final RexWindow window = makeWindow(partitionKeys, orderKeys, lowerBound, upperBound, physical); final RexOver over = new RexOver(type, operator, exprs, window); RexNode result = over; // This should be correct but need time to go over test results. // Also want to look at combing with section below. if (nullWhenCountZero) { final RelDataType bigintType = getTypeFactory().createSqlType(SqlTypeName.BIGINT); result = makeCall( SqlStdOperatorTable.CASE, makeCall( SqlStdOperatorTable.GREATER_THAN, new RexOver(bigintType, SqlStdOperatorTable.COUNT, exprs, window), makeLiteral(BigDecimal.ZERO, bigintType, SqlTypeName.DECIMAL)), ensureType( type, // SUM0 is non-nullable, thus need a cast new RexOver( typeFactory.createTypeWithNullability(type, false), operator, exprs, window), false), makeCast(type, constantNull())); } if (!allowPartial) { Util.permAssert(physical, "DISALLOW PARTIAL over RANGE"); final RelDataType bigintType = getTypeFactory().createSqlType(SqlTypeName.BIGINT); // todo: read bound result = makeCall( SqlStdOperatorTable.CASE, makeCall( SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, new RexOver( bigintType, SqlStdOperatorTable.COUNT, ImmutableList.<RexNode>of(), window), makeLiteral(BigDecimal.valueOf(2), bigintType, SqlTypeName.DECIMAL)), result, constantNull); } return result; }
/** * Resolves a multi-part identifier such as "SCHEMA.EMP.EMPNO" to a namespace. The returned * namespace, never null, may represent a schema, table, column, etc. */ public static SqlValidatorNamespace lookup(SqlValidatorScope scope, List<String> names) { assert names.size() > 0; final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl(); scope.resolve(ImmutableList.of(names.get(0)), false, resolved); assert resolved.count() == 1; SqlValidatorNamespace namespace = resolved.only().namespace; for (String name : Util.skip(names)) { namespace = namespace.lookupChild(name); assert namespace != null; } return namespace; }
/** @see RelMetadataQuery#getPulledUpPredicates(RelNode) */ public RelOptPredicateList getPredicates(RelSubset r, RelMetadataQuery mq) { if (!Bug.CALCITE_1048_FIXED) { return RelOptPredicateList.EMPTY; } RelOptPredicateList list = null; for (RelNode r2 : r.getRels()) { RelOptPredicateList list2 = mq.getPulledUpPredicates(r2); if (list2 != null) { list = list == null ? list2 : list.union(list2); } } return Util.first(list, RelOptPredicateList.EMPTY); }
public Double getMaxRowCount(RelSubset rel, RelMetadataQuery mq) { // FIXME This is a short-term fix for [CALCITE-1018]. A complete // solution will come with [CALCITE-1048]. Util.discard(Bug.CALCITE_1048_FIXED); for (RelNode node : rel.getRels()) { if (node instanceof Sort) { Sort sort = (Sort) node; if (sort.fetch != null) { return (double) RexLiteral.intValue(sort.fetch); } } } return Double.POSITIVE_INFINITY; }
/** * Extracts the string value from a string literal, a chain of string literals, or a CAST of a * string literal. * * @deprecated Use {@link #value(SqlNode)} */ @Deprecated // to be removed before 2.0 public static String stringValue(SqlNode node) { if (node instanceof SqlLiteral) { SqlLiteral literal = (SqlLiteral) node; assert SqlTypeUtil.inCharFamily(literal.getTypeName()); return literal.toValue(); } else if (SqlUtil.isLiteralChain(node)) { final SqlLiteral literal = SqlLiteralChainOperator.concatenateOperands((SqlCall) node); assert SqlTypeUtil.inCharFamily(literal.getTypeName()); return literal.toValue(); } else if (node instanceof SqlCall && ((SqlCall) node).getOperator() == SqlStdOperatorTable.CAST) { return stringValue(((SqlCall) node).operand(0)); } else { throw Util.newInternal("invalid string literal: " + node); } }
/** * Extracts the value from a literal. * * <p>Cases: * * <ul> * <li>If the node is a character literal, a chain of string literals, or a CAST of a character * literal, returns the value as a {@link NlsString}. * <li>If the node is a numeric literal, or a negated numeric literal, returns the value as a * {@link BigDecimal}. * <li>If the node is a {@link SqlIntervalQualifier}, returns its {@link TimeUnitRange}. * <li>If the node is INTERVAL_DAY_TIME in {@link SqlTypeFamily}, returns its sign multiplied by * its millisecond equivalent value * <li>If the node is INTERVAL_YEAR_MONTH in {@link SqlTypeFamily}, returns its sign multiplied * by its months equivalent value * <li>Otherwise the behavior is not specified. * </ul> */ public static Comparable value(SqlNode node) { if (node instanceof SqlLiteral) { SqlLiteral literal = (SqlLiteral) node; switch (literal.getTypeName().getFamily()) { case CHARACTER: return (NlsString) literal.value; case NUMERIC: return (BigDecimal) literal.value; case INTERVAL_YEAR_MONTH: final SqlIntervalLiteral.IntervalValue valMonth = (SqlIntervalLiteral.IntervalValue) literal.value; return valMonth.getSign() * SqlParserUtil.intervalToMonths(valMonth); case INTERVAL_DAY_TIME: final SqlIntervalLiteral.IntervalValue valTime = (SqlIntervalLiteral.IntervalValue) literal.value; return valTime.getSign() * SqlParserUtil.intervalToMillis(valTime); } } if (SqlUtil.isLiteralChain(node)) { assert node instanceof SqlCall; final SqlLiteral literal = SqlLiteralChainOperator.concatenateOperands((SqlCall) node); assert SqlTypeUtil.inCharFamily(literal.getTypeName()); return (NlsString) literal.value; } if (node instanceof SqlIntervalQualifier) { SqlIntervalQualifier qualifier = (SqlIntervalQualifier) node; return qualifier.timeUnitRange; } switch (node.getKind()) { case CAST: assert node instanceof SqlCall; return value(((SqlCall) node).operand(0)); case MINUS_PREFIX: assert node instanceof SqlCall; Comparable o = value(((SqlCall) node).operand(0)); if (o instanceof BigDecimal) { BigDecimal bigDecimal = (BigDecimal) o; return bigDecimal.negate(); } // fall through default: throw Util.newInternal("invalid literal: " + node); } }
/** * Returns the long value of this literal. * * @param exact Whether the value has to be exact. If true, and the literal is a fraction (e.g. * 3.14), throws. If false, discards the fractional part of the value. * @return Long value of this literal */ public long longValue(boolean exact) { switch (typeName) { case DECIMAL: case DOUBLE: BigDecimal bd = (BigDecimal) value; if (exact) { try { return bd.longValueExact(); } catch (ArithmeticException e) { throw SqlUtil.newContextException( getParserPosition(), RESOURCE.numberLiteralOutOfRange(bd.toString())); } } else { return bd.longValue(); } default: throw Util.unexpected(typeName); } }
public RelDataType createSqlType(RelDataTypeFactory typeFactory) { BitString bitString; switch (typeName) { case NULL: case BOOLEAN: RelDataType ret = typeFactory.createSqlType(typeName); ret = typeFactory.createTypeWithNullability(ret, null == value); return ret; case BINARY: bitString = (BitString) value; int bitCount = bitString.getBitCount(); return typeFactory.createSqlType(SqlTypeName.BINARY, bitCount / 8); case CHAR: NlsString string = (NlsString) value; Charset charset = string.getCharset(); if (null == charset) { charset = typeFactory.getDefaultCharset(); } SqlCollation collation = string.getCollation(); if (null == collation) { collation = SqlCollation.COERCIBLE; } RelDataType type = typeFactory.createSqlType(SqlTypeName.CHAR, string.getValue().length()); type = typeFactory.createTypeWithCharsetAndCollation(type, charset, collation); return type; case INTERVAL_YEAR_MONTH: case INTERVAL_DAY_TIME: SqlIntervalLiteral.IntervalValue intervalValue = (SqlIntervalLiteral.IntervalValue) value; return typeFactory.createSqlIntervalType(intervalValue.getIntervalQualifier()); case SYMBOL: return typeFactory.createSqlType(SqlTypeName.SYMBOL); case INTEGER: // handled in derived class case TIME: // handled in derived class case VARCHAR: // should never happen case VARBINARY: // should never happen default: throw Util.needToImplement(toString() + ", operand=" + value); } }
/** * Derives an alias for a node, and invents a mangled identifier if it cannot. * * <p>Examples: * * <ul> * <li>Alias: "1 + 2 as foo" yields "foo" * <li>Identifier: "foo.bar.baz" yields "baz" * <li>Anything else yields "expr$<i>ordinal</i>" * </ul> * * @return An alias, if one can be derived; or a synthetic alias "expr$<i>ordinal</i>" if ordinal * < 0; otherwise null */ public static String getAlias(SqlNode node, int ordinal) { switch (node.getKind()) { case AS: // E.g. "1 + 2 as foo" --> "foo" return ((SqlCall) node).operand(1).toString(); case OVER: // E.g. "bids over w" --> "bids" return getAlias(((SqlCall) node).operand(0), ordinal); case IDENTIFIER: // E.g. "foo.bar" --> "bar" return Util.last(((SqlIdentifier) node).names); default: if (ordinal < 0) { return null; } else { return SqlUtil.deriveAliasFromOrdinal(ordinal); } } }
/** * Runs with query #i. * * @param i Ordinal of query, per the benchmark, 1-based * @param enable Whether to enable query execution. If null, use the value of {@link #ENABLE}. * Pass true only for 'fast' tests that do not read any data. */ private CalciteAssert.AssertQuery query(int i, Boolean enable) { return with(Util.first(enable, ENABLE)) .query(QUERIES.get(i - 1).replaceAll("tpch\\.", "tpch_01.")); }
/** * Validates the parse tree of a SQL statement, and provides semantic information about the parse * tree. * * <p>To create an instance of the default validator implementation, call {@link * SqlValidatorUtil#newValidator}. * * <h2>Visitor pattern</h2> * * <p>The validator interface is an instance of the {@link * org.apache.calcite.util.Glossary#VISITOR_PATTERN visitor pattern}. Implementations of the {@link * SqlNode#validate} method call the <code>validateXxx</code> method appropriate to the kind of * node: * * <ul> * <li>{@link SqlLiteral#validate(SqlValidator, SqlValidatorScope)} calls {@link * #validateLiteral(org.apache.calcite.sql.SqlLiteral)}; * <li>{@link SqlCall#validate(SqlValidator, SqlValidatorScope)} calls {@link * #validateCall(SqlCall, SqlValidatorScope)}; * <li>and so forth. * </ul> * * <p>The {@link SqlNode#validateExpr(SqlValidator, SqlValidatorScope)} method is as {@link * SqlNode#validate(SqlValidator, SqlValidatorScope)} but is called when the node is known to be a * scalar expression. * * <h2>Scopes and namespaces</h2> * * <p>In order to resolve names to objects, the validator builds a map of the structure of the * query. This map consists of two types of objects. A {@link SqlValidatorScope} describes the * tables and columns accessible at a particular point in the query; and a {@link * SqlValidatorNamespace} is a description of a data source used in a query. * * <p>There are different kinds of namespace for different parts of the query. for example {@link * IdentifierNamespace} for table names, {@link SelectNamespace} for SELECT queries, {@link * SetopNamespace} for UNION, EXCEPT and INTERSECT. A validator is allowed to wrap namespaces in * other objects which implement {@link SqlValidatorNamespace}, so don't try to cast your namespace * or use <code>instanceof</code>; use {@link SqlValidatorNamespace#unwrap(Class)} and {@link * SqlValidatorNamespace#isWrapperFor(Class)} instead. * * <p>The validator builds the map by making a quick scan over the query when the root {@link * SqlNode} is first provided. Thereafter, it supplies the correct scope or namespace object when it * calls validation methods. * * <p>The methods {@link #getSelectScope}, {@link #getFromScope}, {@link #getWhereScope}, {@link * #getGroupScope}, {@link #getHavingScope}, {@link #getOrderScope} and {@link #getJoinScope} get * the correct scope to resolve names in a particular clause of a SQL statement. */ public interface SqlValidator { /** Whether to follow the SQL standard strictly. */ boolean STRICT = Util.getBooleanProperty("calcite.strict.sql"); // ~ Methods ---------------------------------------------------------------- /** * Returns the dialect of SQL (SQL:2003, etc.) this validator recognizes. Default is {@link * SqlConformance#DEFAULT}. * * @return dialect of SQL this validator recognizes */ SqlConformance getConformance(); /** * Returns the catalog reader used by this validator. * * @return catalog reader */ SqlValidatorCatalogReader getCatalogReader(); /** * Returns the operator table used by this validator. * * @return operator table */ SqlOperatorTable getOperatorTable(); /** * Validates an expression tree. You can call this method multiple times, but not reentrantly. * * @param topNode top of expression tree to be validated * @return validated tree (possibly rewritten) */ SqlNode validate(SqlNode topNode); /** * Validates an expression tree. You can call this method multiple times, but not reentrantly. * * @param topNode top of expression tree to be validated * @param nameToTypeMap map of simple name to {@link RelDataType}; used to resolve {@link * SqlIdentifier} references * @return validated tree (possibly rewritten) */ SqlNode validateParameterizedExpression(SqlNode topNode, Map<String, RelDataType> nameToTypeMap); /** * Checks that a query is valid. * * <p>Valid queries include: * * <ul> * <li><code>SELECT</code> statement, * <li>set operation (<code>UNION</code>, <code>INTERSECT</code>, <code> * EXCEPT</code>) * <li>identifier (e.g. representing use of a table in a FROM clause) * <li>query aliased with the <code>AS</code> operator * </ul> * * @param node Query node * @param scope Scope in which the query occurs * @param targetRowType Desired row type, must not be null, may be the data type 'unknown'. * @throws RuntimeException if the query is not valid */ void validateQuery(SqlNode node, SqlValidatorScope scope, RelDataType targetRowType); /** * Returns the type assigned to a node by validation. * * @param node the node of interest * @return validated type, never null */ RelDataType getValidatedNodeType(SqlNode node); /** * Returns the type assigned to a node by validation, or null if unknown. This allows for queries * against nodes such as aliases, which have no type of their own. If you want to assert that the * node of interest must have a type, use {@link #getValidatedNodeType} instead. * * @param node the node of interest * @return validated type, or null if unknown or not applicable */ RelDataType getValidatedNodeTypeIfKnown(SqlNode node); /** * Resolves an identifier to a fully-qualified name. * * @param id Identifier * @param scope Naming scope */ void validateIdentifier(SqlIdentifier id, SqlValidatorScope scope); /** * Validates a literal. * * @param literal Literal */ void validateLiteral(SqlLiteral literal); /** * Validates a {@link SqlIntervalQualifier} * * @param qualifier Interval qualifier */ void validateIntervalQualifier(SqlIntervalQualifier qualifier); /** * Validates an INSERT statement. * * @param insert INSERT statement */ void validateInsert(SqlInsert insert); /** * Validates an UPDATE statement. * * @param update UPDATE statement */ void validateUpdate(SqlUpdate update); /** * Validates a DELETE statement. * * @param delete DELETE statement */ void validateDelete(SqlDelete delete); /** * Validates a MERGE statement. * * @param merge MERGE statement */ void validateMerge(SqlMerge merge); /** * Validates a data type expression. * * @param dataType Data type */ void validateDataType(SqlDataTypeSpec dataType); /** * Validates a dynamic parameter. * * @param dynamicParam Dynamic parameter */ void validateDynamicParam(SqlDynamicParam dynamicParam); /** * Validates the right-hand side of an OVER expression. It might be either an {@link SqlIdentifier * identifier} referencing a window, or an {@link SqlWindow inline window specification}. * * @param windowOrId SqlNode that can be either SqlWindow with all the components of a window spec * or a SqlIdentifier with the name of a window spec. * @param scope Naming scope * @param call the SqlNode if a function call if the window is attached to one. */ void validateWindow(SqlNode windowOrId, SqlValidatorScope scope, SqlCall call); /** * Validates a call to an operator. * * @param call Operator call * @param scope Naming scope */ void validateCall(SqlCall call, SqlValidatorScope scope); /** * Validates parameters for aggregate function. * * @param aggCall Function containing COLUMN_LIST parameter * @param filter Filter, or null * @param scope Syntactic scope */ void validateAggregateParams(SqlCall aggCall, SqlNode filter, SqlValidatorScope scope); /** * Validates a COLUMN_LIST parameter * * @param function function containing COLUMN_LIST parameter * @param argTypes function arguments * @param operands operands passed into the function call */ void validateColumnListParams( SqlFunction function, List<RelDataType> argTypes, List<SqlNode> operands); /** * Derives the type of a node in a given scope. If the type has already been inferred, returns the * previous type. * * @param scope Syntactic scope * @param operand Parse tree node * @return Type of the SqlNode. Should never return <code>NULL</code> */ RelDataType deriveType(SqlValidatorScope scope, SqlNode operand); /** * Adds "line x, column y" context to a validator exception. * * <p>Note that the input exception is checked (it derives from {@link Exception}) and the output * exception is unchecked (it derives from {@link RuntimeException}). This is intentional -- it * should remind code authors to provide context for their validation errors. * * @param node The place where the exception occurred, not null * @param e The validation error * @return Exception containing positional information, never null */ CalciteContextException newValidationError( SqlNode node, Resources.ExInst<SqlValidatorException> e); /** * Returns whether a SELECT statement is an aggregation. Criteria are: (1) contains GROUP BY, or * (2) contains HAVING, or (3) SELECT or ORDER BY clause contains aggregate functions. (Windowed * aggregate functions, such as <code>SUM(x) OVER w</code>, don't count.) * * @param select SELECT statement * @return whether SELECT statement is an aggregation */ boolean isAggregate(SqlSelect select); /** * Returns whether a select list expression is an aggregate function. * * @param selectNode Expression in SELECT clause * @return whether expression is an aggregate function */ @Deprecated // to be removed before 2.0 boolean isAggregate(SqlNode selectNode); /** * Converts a window specification or window name into a fully-resolved window specification. For * example, in <code>SELECT sum(x) OVER (PARTITION * BY x ORDER BY y), sum(y) OVER w1, sum(z) OVER (w ORDER BY y) FROM t * WINDOW w AS (PARTITION BY x)</code> all aggregations have the same resolved window * specification <code>(PARTITION BY x ORDER BY y)</code>. * * @param windowOrRef Either the name of a window (a {@link SqlIdentifier}) or a window * specification (a {@link SqlWindow}). * @param scope Scope in which to resolve window names * @param populateBounds Whether to populate bounds. Doing so may alter the definition of the * window. It is recommended that populate bounds when translating to physical algebra, but * not when validating. * @return A window * @throws RuntimeException Validation exception if window does not exist */ SqlWindow resolveWindow(SqlNode windowOrRef, SqlValidatorScope scope, boolean populateBounds); /** * Finds the namespace corresponding to a given node. * * <p>For example, in the query <code>SELECT * FROM (SELECT * FROM t), t1 AS * alias</code>, the both items in the FROM clause have a corresponding namespace. * * @param node Parse tree node * @return namespace of node */ SqlValidatorNamespace getNamespace(SqlNode node); /** * Derives an alias for an expression. If no alias can be derived, returns null if <code>ordinal * </code> is less than zero, otherwise generates an alias <code>EXPR$<i>ordinal</i></code>. * * @param node Expression * @param ordinal Ordinal of expression * @return derived alias, or null if no alias can be derived and ordinal is less than zero */ String deriveAlias(SqlNode node, int ordinal); /** * Returns a list of expressions, with every occurrence of "*" or "TABLE.*" expanded. * * @param selectList Select clause to be expanded * @param query Query * @param includeSystemVars Whether to include system variables * @return expanded select clause */ SqlNodeList expandStar(SqlNodeList selectList, SqlSelect query, boolean includeSystemVars); /** * Returns the scope that expressions in the WHERE and GROUP BY clause of this query should use. * This scope consists of the tables in the FROM clause, and the enclosing scope. * * @param select Query * @return naming scope of WHERE clause */ SqlValidatorScope getWhereScope(SqlSelect select); /** * Returns the type factory used by this validator. * * @return type factory */ RelDataTypeFactory getTypeFactory(); /** * Saves the type of a {@link SqlNode}, now that it has been validated. * * @param node A SQL parse tree node, never null * @param type Its type; must not be null * @deprecated This method should not be in the {@link SqlValidator} interface. The validator * should drive the type-derivation process, and store nodes' types when they have been * derived. */ void setValidatedNodeType(SqlNode node, RelDataType type); /** * Removes a node from the set of validated nodes * * @param node node to be removed */ void removeValidatedNodeType(SqlNode node); /** * Returns an object representing the "unknown" type. * * @return unknown type */ RelDataType getUnknownType(); /** * Returns the appropriate scope for validating a particular clause of a SELECT statement. * * <p>Consider * * <blockquote> * * <pre><code>SELECT * * FROM foo * WHERE EXISTS ( * SELECT deptno AS x * FROM emp * JOIN dept ON emp.deptno = dept.deptno * WHERE emp.deptno = 5 * GROUP BY deptno * ORDER BY x)</code></pre> * * </blockquote> * * <p>What objects can be seen in each part of the sub-query? * * <ul> * <li>In FROM ({@link #getFromScope} , you can only see 'foo'. * <li>In WHERE ({@link #getWhereScope}), GROUP BY ({@link #getGroupScope}), SELECT ({@code * getSelectScope}), and the ON clause of the JOIN ({@link #getJoinScope}) you can see * 'emp', 'dept', and 'foo'. * <li>In ORDER BY ({@link #getOrderScope}), you can see the column alias 'x'; and tables 'emp', * 'dept', and 'foo'. * </ul> * * @param select SELECT statement * @return naming scope for SELECT statement */ SqlValidatorScope getSelectScope(SqlSelect select); /** * Returns the scope for resolving the SELECT, GROUP BY and HAVING clauses. Always a {@link * SelectScope}; if this is an aggregation query, the {@link AggregatingScope} is stripped away. * * @param select SELECT statement * @return naming scope for SELECT statement, sans any aggregating scope */ SelectScope getRawSelectScope(SqlSelect select); /** * Returns a scope containing the objects visible from the FROM clause of a query. * * @param select SELECT statement * @return naming scope for FROM clause */ SqlValidatorScope getFromScope(SqlSelect select); /** * Returns a scope containing the objects visible from the ON and USING sections of a JOIN clause. * * @param node The item in the FROM clause which contains the ON or USING expression * @return naming scope for JOIN clause * @see #getFromScope */ SqlValidatorScope getJoinScope(SqlNode node); /** * Returns a scope containing the objects visible from the GROUP BY clause of a query. * * @param select SELECT statement * @return naming scope for GROUP BY clause */ SqlValidatorScope getGroupScope(SqlSelect select); /** * Returns a scope containing the objects visible from the HAVING clause of a query. * * @param select SELECT statement * @return naming scope for HAVING clause */ SqlValidatorScope getHavingScope(SqlSelect select); /** * Returns the scope that expressions in the SELECT and HAVING clause of this query should use. * This scope consists of the FROM clause and the enclosing scope. If the query is aggregating, * only columns in the GROUP BY clause may be used. * * @param select SELECT statement * @return naming scope for ORDER BY clause */ SqlValidatorScope getOrderScope(SqlSelect select); /** * Declares a SELECT expression as a cursor. * * @param select select expression associated with the cursor * @param scope scope of the parent query associated with the cursor */ void declareCursor(SqlSelect select, SqlValidatorScope scope); /** Pushes a new instance of a function call on to a function call stack. */ void pushFunctionCall(); /** Removes the topmost entry from the function call stack. */ void popFunctionCall(); /** * Retrieves the name of the parent cursor referenced by a column list parameter. * * @param columnListParamName name of the column list parameter * @return name of the parent cursor */ String getParentCursor(String columnListParamName); /** * Enables or disables expansion of identifiers other than column references. * * @param expandIdentifiers new setting */ void setIdentifierExpansion(boolean expandIdentifiers); /** * Enables or disables expansion of column references. (Currently this does not apply to the ORDER * BY clause; may be fixed in the future.) * * @param expandColumnReferences new setting */ void setColumnReferenceExpansion(boolean expandColumnReferences); /** @return whether column reference expansion is enabled */ boolean getColumnReferenceExpansion(); /** * Sets how NULL values should be collated if an ORDER BY item does not contain NULLS FIRST or * NULLS LAST. */ void setDefaultNullCollation(NullCollation nullCollation); /** * Returns how NULL values should be collated if an ORDER BY item does not contain NULLS FIRST or * NULLS LAST. */ NullCollation getDefaultNullCollation(); /** * Returns expansion of identifiers. * * @return whether this validator should expand identifiers */ boolean shouldExpandIdentifiers(); /** * Enables or disables rewrite of "macro-like" calls such as COALESCE. * * @param rewriteCalls new setting */ void setCallRewrite(boolean rewriteCalls); /** * Derives the type of a constructor. * * @param scope Scope * @param call Call * @param unresolvedConstructor TODO * @param resolvedConstructor TODO * @param argTypes Types of arguments * @return Resolved type of constructor */ RelDataType deriveConstructorType( SqlValidatorScope scope, SqlCall call, SqlFunction unresolvedConstructor, SqlFunction resolvedConstructor, List<RelDataType> argTypes); /** * Handles a call to a function which cannot be resolved. Returns a an appropriately descriptive * error, which caller must throw. * * @param call Call * @param unresolvedFunction Overloaded function which is the target of the call * @param argTypes Types of arguments * @param argNames Names of arguments, or null if call by position */ CalciteException handleUnresolvedFunction( SqlCall call, SqlFunction unresolvedFunction, List<RelDataType> argTypes, List<String> argNames); /** * Expands an expression in the ORDER BY clause into an expression with the same semantics as * expressions in the SELECT clause. * * <p>This is made necessary by a couple of dialect 'features': * * <ul> * <li><b>ordinal expressions</b>: In "SELECT x, y FROM t ORDER BY 2", the expression "2" is * shorthand for the 2nd item in the select clause, namely "y". * <li><b>alias references</b>: In "SELECT x AS a, y FROM t ORDER BY a", the expression "a" is * shorthand for the item in the select clause whose alias is "a" * </ul> * * @param select Select statement which contains ORDER BY * @param orderExpr Expression in the ORDER BY clause. * @return Expression translated into SELECT clause semantics */ SqlNode expandOrderExpr(SqlSelect select, SqlNode orderExpr); /** * Expands an expression. * * @param expr Expression * @param scope Scope * @return Expanded expression */ SqlNode expand(SqlNode expr, SqlValidatorScope scope); /** * Returns whether a field is a system field. Such fields may have particular properties such as * sortedness and nullability. * * <p>In the default implementation, always returns {@code false}. * * @param field Field * @return whether field is a system field */ boolean isSystemField(RelDataTypeField field); /** * Returns a description of how each field in the row type maps to a catalog, schema, table and * column in the schema. * * <p>The returned list is never null, and has one element for each field in the row type. Each * element is a list of four elements (catalog, schema, table, column), or may be null if the * column is an expression. * * @param sqlQuery Query * @return Description of how each field in the row type maps to a schema object */ List<List<String>> getFieldOrigins(SqlNode sqlQuery); /** * Returns a record type that contains the name and type of each parameter. Returns a record type * with no fields if there are no parameters. * * @param sqlQuery Query * @return Record type */ RelDataType getParameterRowType(SqlNode sqlQuery); /** * Returns the scope of an OVER or VALUES node. * * @param node Node * @return Scope */ SqlValidatorScope getOverScope(SqlNode node); /** * Validates that a query is capable of producing a return of given modality (relational or * streaming). * * @param select Query * @param modality Modality (streaming or relational) * @param fail Whether to throw a user error if does not support required modality * @return whether query supports the given modality */ boolean validateModality(SqlSelect select, SqlModality modality, boolean fail); void validateWith(SqlWith with, SqlValidatorScope scope); void validateWithItem(SqlWithItem withItem); void validateSequenceValue(SqlValidatorScope scope, SqlIdentifier id); SqlValidatorScope getWithScope(SqlNode withItem); }
@Override public double estimateRowCount(RelMetadataQuery mq) { return Util.first(RelMdUtil.getSemiJoinRowCount(mq, left, right, joinType, condition), 1D); }
/** * Checks whether an exception matches the expected pattern. If <code> * sap</code> contains an error location, checks this too. * * @param ex Exception thrown * @param expectedMsgPattern Expected pattern * @param sap Query and (optional) position in query */ public static void checkEx( Throwable ex, String expectedMsgPattern, SqlParserUtil.StringAndPos sap) { if (null == ex) { if (expectedMsgPattern == null) { // No error expected, and no error happened. return; } else { throw new AssertionError( "Expected query to throw exception, " + "but it did not; query [" + sap.sql + "]; expected [" + expectedMsgPattern + "]"); } } Throwable actualException = ex; String actualMessage = actualException.getMessage(); int actualLine = -1; int actualColumn = -1; int actualEndLine = 100; int actualEndColumn = 99; // Search for an CalciteContextException somewhere in the stack. CalciteContextException ece = null; for (Throwable x = ex; x != null; x = x.getCause()) { if (x instanceof CalciteContextException) { ece = (CalciteContextException) x; break; } if (x.getCause() == x) { break; } } // Search for a SqlParseException -- with its position set -- somewhere // in the stack. SqlParseException spe = null; for (Throwable x = ex; x != null; x = x.getCause()) { if ((x instanceof SqlParseException) && (((SqlParseException) x).getPos() != null)) { spe = (SqlParseException) x; break; } if (x.getCause() == x) { break; } } if (ece != null) { actualLine = ece.getPosLine(); actualColumn = ece.getPosColumn(); actualEndLine = ece.getEndPosLine(); actualEndColumn = ece.getEndPosColumn(); if (ece.getCause() != null) { actualException = ece.getCause(); actualMessage = actualException.getMessage(); } } else if (spe != null) { actualLine = spe.getPos().getLineNum(); actualColumn = spe.getPos().getColumnNum(); actualEndLine = spe.getPos().getEndLineNum(); actualEndColumn = spe.getPos().getEndColumnNum(); if (spe.getCause() != null) { actualException = spe.getCause(); actualMessage = actualException.getMessage(); } } else { final String message = ex.getMessage(); if (message != null) { Matcher matcher = LINE_COL_TWICE_PATTERN.matcher(message); if (matcher.matches()) { actualLine = Integer.parseInt(matcher.group(1)); actualColumn = Integer.parseInt(matcher.group(2)); actualEndLine = Integer.parseInt(matcher.group(3)); actualEndColumn = Integer.parseInt(matcher.group(4)); actualMessage = matcher.group(5); } else { matcher = LINE_COL_PATTERN.matcher(message); if (matcher.matches()) { actualLine = Integer.parseInt(matcher.group(1)); actualColumn = Integer.parseInt(matcher.group(2)); } } } } if (null == expectedMsgPattern) { if (null != actualException) { actualException.printStackTrace(); fail( "Validator threw unexpected exception" + "; query [" + sap.sql + "]; exception [" + actualMessage + "]; class [" + actualException.getClass() + "]; pos [line " + actualLine + " col " + actualColumn + " thru line " + actualLine + " col " + actualColumn + "]"); } } else { if (null == actualException) { fail( "Expected validator to throw " + "exception, but it did not; query [" + sap.sql + "]; expected [" + expectedMsgPattern + "]"); } else { String sqlWithCarets; if ((actualColumn <= 0) || (actualLine <= 0) || (actualEndColumn <= 0) || (actualEndLine <= 0)) { if (sap.pos != null) { AssertionError e = new AssertionError( "Expected error to have position," + " but actual error did not: " + " actual pos [line " + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "]"); e.initCause(actualException); throw e; } sqlWithCarets = sap.sql; } else { sqlWithCarets = SqlParserUtil.addCarets( sap.sql, actualLine, actualColumn, actualEndLine, actualEndColumn + 1); if (sap.pos == null) { throw new AssertionError( "Actual error had a position, but expected error" + " did not. Add error position carets to sql:\n" + sqlWithCarets); } } if (actualMessage != null) { actualMessage = Util.toLinux(actualMessage); } if ((actualMessage == null) || !actualMessage.matches(expectedMsgPattern)) { actualException.printStackTrace(); final String actualJavaRegexp = (actualMessage == null) ? "null" : TestUtil.quoteForJava(TestUtil.quotePattern(actualMessage)); fail( "Validator threw different " + "exception than expected; query [" + sap.sql + "];\n" + " expected pattern [" + expectedMsgPattern + "];\n" + " actual [" + actualMessage + "];\n" + " actual as java regexp [" + actualJavaRegexp + "]; pos [" + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "]; sql [" + sqlWithCarets + "]"); } else if ((sap.pos != null) && ((actualLine != sap.pos.getLineNum()) || (actualColumn != sap.pos.getColumnNum()) || (actualEndLine != sap.pos.getEndLineNum()) || (actualEndColumn != sap.pos.getEndColumnNum()))) { fail( "Validator threw expected " + "exception [" + actualMessage + "];\nbut at pos [line " + actualLine + " col " + actualColumn + " thru line " + actualEndLine + " col " + actualEndColumn + "];\nsql [" + sqlWithCarets + "]"); } } } }
public String apply(String original, int attempt, int size) { return Util.first(original, "EXPR$") + attempt; }
/** * Creates a literal of a given type. The value is assumed to be compatible with the type. * * @param value Value * @param type Type * @param allowCast Whether to allow a cast. If false, value is always a {@link RexLiteral} but * may not be the exact type * @return Simple literal, or cast simple literal */ public RexNode makeLiteral(Object value, RelDataType type, boolean allowCast) { if (value == null) { return makeCast(type, constantNull); } if (type.isNullable()) { final RelDataType typeNotNull = typeFactory.createTypeWithNullability(type, false); RexNode literalNotNull = makeLiteral(value, typeNotNull, allowCast); return makeAbstractCast(type, literalNotNull); } value = clean(value, type); RexLiteral literal; final List<RexNode> operands; switch (type.getSqlTypeName()) { case CHAR: return makeCharLiteral(padRight((NlsString) value, type.getPrecision())); case VARCHAR: literal = makeCharLiteral((NlsString) value); if (allowCast) { return makeCast(type, literal); } else { return literal; } case BINARY: return makeBinaryLiteral(padRight((ByteString) value, type.getPrecision())); case VARBINARY: literal = makeBinaryLiteral((ByteString) value); if (allowCast) { return makeCast(type, literal); } else { return literal; } case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case DECIMAL: return makeExactLiteral((BigDecimal) value, type); case FLOAT: case REAL: case DOUBLE: return makeApproxLiteral((BigDecimal) value, type); case BOOLEAN: return (Boolean) value ? booleanTrue : booleanFalse; case TIME: return makeTimeLiteral((Calendar) value, type.getPrecision()); case DATE: return makeDateLiteral((Calendar) value); case TIMESTAMP: return makeTimestampLiteral((Calendar) value, type.getPrecision()); case INTERVAL_YEAR_MONTH: case INTERVAL_DAY_TIME: return makeIntervalLiteral((BigDecimal) value, type.getIntervalQualifier()); case MAP: final MapSqlType mapType = (MapSqlType) type; @SuppressWarnings("unchecked") final Map<Object, Object> map = (Map) value; operands = new ArrayList<RexNode>(); for (Map.Entry<Object, Object> entry : map.entrySet()) { operands.add(makeLiteral(entry.getKey(), mapType.getKeyType(), allowCast)); operands.add(makeLiteral(entry.getValue(), mapType.getValueType(), allowCast)); } return makeCall(SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR, operands); case ARRAY: final ArraySqlType arrayType = (ArraySqlType) type; @SuppressWarnings("unchecked") final List<Object> listValue = (List) value; operands = new ArrayList<RexNode>(); for (Object entry : listValue) { operands.add(makeLiteral(entry, arrayType.getComponentType(), allowCast)); } return makeCall(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR, operands); case ANY: return makeLiteral(value, guessType(value), allowCast); default: throw Util.unexpected(type.getSqlTypeName()); } }
public String apply(String original, int attempt, int size) { return Util.first(original, "$f") + Math.max(size, attempt); }
@Deprecated // to be removed before 2.0 public JdbcCalc( RelOptCluster cluster, RelTraitSet traitSet, RelNode input, RexProgram program, int flags) { this(cluster, traitSet, input, program); Util.discard(flags); }