All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.rex.RexWindow Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * 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 com.hazelcast.org.apache.calcite.rex;

import com.hazelcast.org.apache.calcite.util.Pair;

import com.hazelcast.com.google.common.base.Preconditions;
import com.hazelcast.com.google.common.collect.ImmutableList;

import java.util.List;
import java.util.Objects;

/**
 * Specification of the window of rows over which a {@link RexOver} windowed
 * aggregate is evaluated.
 *
 * 

Treat it as immutable! */ public class RexWindow { //~ Instance fields -------------------------------------------------------- public final ImmutableList partitionKeys; public final ImmutableList orderKeys; private final RexWindowBound lowerBound; private final RexWindowBound upperBound; private final boolean isRows; private final String digest; public final int nodeCount; //~ Constructors ----------------------------------------------------------- /** * Creates a window. * *

If you need to create a window from outside this package, use * {@link RexBuilder#makeOver}. * *

If {@code orderKeys} is empty the bracket will usually be * "BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING". * *

The digest assumes 'default' brackets, and does not print brackets or * bounds that are the default. * *

If {@code orderKeys} is empty, assumes the bracket is "RANGE BETWEEN * UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING" and does not print the * bracket. * *

  • If {@code orderKeys} is not empty, the default top is "CURRENT ROW". * The default bracket is "RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW", * which will be printed as blank. * "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is different, and is * printed as "ROWS UNBOUNDED PRECEDING". * "ROWS BETWEEN 5 PRECEDING AND CURRENT ROW" is printed as * "ROWS 5 PRECEDING". */ RexWindow( List partitionKeys, List orderKeys, RexWindowBound lowerBound, RexWindowBound upperBound, boolean isRows) { this.partitionKeys = ImmutableList.copyOf(partitionKeys); this.orderKeys = ImmutableList.copyOf(orderKeys); this.lowerBound = Objects.requireNonNull(lowerBound); this.upperBound = Objects.requireNonNull(upperBound); this.isRows = isRows; this.nodeCount = computeCodeCount(); this.digest = computeDigest(); Preconditions.checkArgument( !(lowerBound.isUnbounded() && lowerBound.isPreceding() && upperBound.isUnbounded() && upperBound.isFollowing() && isRows), "use RANGE for unbounded, not ROWS"); } //~ Methods ---------------------------------------------------------------- public String toString() { return digest; } public int hashCode() { return digest.hashCode(); } public boolean equals(Object that) { if (that instanceof RexWindow) { RexWindow window = (RexWindow) that; return digest.equals(window.digest); } return false; } private String computeDigest() { return appendDigest_(new StringBuilder(), true).toString(); } StringBuilder appendDigest(StringBuilder sb, boolean allowFraming) { if (allowFraming) { // digest was calculated with allowFraming=true; reuse it return sb.append(digest); } else { return appendDigest_(sb, allowFraming); } } private StringBuilder appendDigest_(StringBuilder sb, boolean allowFraming) { final int initialLength = sb.length(); if (partitionKeys.size() > 0) { sb.append("PARTITION BY "); for (int i = 0; i < partitionKeys.size(); i++) { if (i > 0) { sb.append(", "); } sb.append(partitionKeys.get(i)); } } if (orderKeys.size() > 0) { sb.append(sb.length() > initialLength ? " ORDER BY " : "ORDER BY "); for (int i = 0; i < orderKeys.size(); i++) { if (i > 0) { sb.append(", "); } sb.append(orderKeys.get(i)); } } // There are 3 reasons to skip the ROWS/RANGE clause. // 1. If this window is being used with a RANK-style function that does not // allow framing, or // 2. If there is no ORDER BY (in which case a frame is invalid), or // 3. If the ROWS/RANGE clause is the default, "RANGE BETWEEN UNBOUNDED // PRECEDING AND CURRENT ROW" if (!allowFraming // 1 || orderKeys.isEmpty() // 2 || (lowerBound.isUnbounded() // 3 && lowerBound.isPreceding() && upperBound.isCurrentRow() && !isRows)) { // No ROWS or RANGE clause } else if (upperBound.isCurrentRow()) { // Per MSSQL: If ROWS/RANGE is specified and // is used for (short syntax) then this // specification is used for the window frame boundary starting point and // CURRENT ROW is used for the boundary ending point. For example // "ROWS 5 PRECEDING" is equal to "ROWS BETWEEN 5 PRECEDING AND CURRENT // ROW". // // By similar reasoning to (3) above, we print the shorter option if it is // the default. If the RexWindow is, say, "ROWS BETWEEN 5 PRECEDING AND // CURRENT ROW", we output "ROWS 5 PRECEDING" because it is equivalent and // is shorter. sb.append(sb.length() > initialLength ? (isRows ? " ROWS " : " RANGE ") : (isRows ? "ROWS " : "RANGE ")) .append(lowerBound); } else { sb.append(sb.length() > initialLength ? (isRows ? " ROWS BETWEEN " : " RANGE BETWEEN ") : (isRows ? "ROWS BETWEEN " : "RANGE BETWEEN ")) .append(lowerBound) .append(" AND ") .append(upperBound); } return sb; } public RexWindowBound getLowerBound() { return lowerBound; } public RexWindowBound getUpperBound() { return upperBound; } public boolean isRows() { return isRows; } private int computeCodeCount() { return RexUtil.nodeCount(partitionKeys) + RexUtil.nodeCount(Pair.left(orderKeys)) + (lowerBound == null ? 0 : lowerBound.nodeCount()) + (upperBound == null ? 0 : upperBound.nodeCount()); } }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy