org.hsqldb.ParserDQL Maven / Gradle / Ivy
/* Copyright (c) 2001-2022, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.HsqlNameManager.SimpleName;
import org.hsqldb.QueryExpression.RecursiveQuerySettings;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.Iterator;
import org.hsqldb.lib.List;
import org.hsqldb.lib.LongDeque;
import org.hsqldb.lib.OrderedHashMap;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.lib.OrderedIntKeyHashMap;
import org.hsqldb.map.BitMap;
import org.hsqldb.map.ValuePool;
import org.hsqldb.result.ResultConstants;
import org.hsqldb.result.ResultProperties;
import org.hsqldb.types.ArrayType;
import org.hsqldb.types.BinaryType;
import org.hsqldb.types.BlobType;
import org.hsqldb.types.CharacterType;
import org.hsqldb.types.Charset;
import org.hsqldb.types.ClobType;
import org.hsqldb.types.Collation;
import org.hsqldb.types.DTIType;
import org.hsqldb.types.IntervalType;
import org.hsqldb.types.NumberType;
import org.hsqldb.types.Type;
import org.hsqldb.types.Types;
import org.hsqldb.types.UserTypeModifier;
/**
* Parser for DQL statements
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.7.0
* @since 1.9.0
*/
public class ParserDQL extends ParserBase {
protected Database database;
protected Session session;
protected final CompileContext compileContext;
/**
* Constructs a new Parser object with the given context.
*
* @param session the connected context
* @param scanner the token source from which to parse commands
*/
ParserDQL(Session session, Scanner scanner, CompileContext baseContext) {
super(scanner);
this.session = session;
this.database = session.getDatabase();
this.compileContext = new CompileContext(session, this, baseContext);
}
/**
* Resets this parse context with the given SQL character sequence.
*
* @param sql a new SQL character sequence to replace the current one
*/
void reset(Session session, String sql) {
super.reset(session, sql);
compileContext.reset();
lastError = null;
}
void checkIsSchemaObjectName() {
if (database.sqlEnforceNames) {
checkIsNonReservedIdentifier();
} else {
checkIsNonCoreReservedIdentifier();
}
if (database.sqlRegularNames) {
checkIsIrregularCharInIdentifier();
}
}
Type readTypeDefinition(boolean allowCollation, boolean includeUserTypes) {
int typeNumber = Integer.MIN_VALUE;
boolean hasLength = false;
boolean hasScale = false;
boolean isCharacter = false;
boolean isIgnoreCase = false;
boolean readByteOrChar = false;
boolean enforceSize = database.sqlEnforceSize;
boolean acceptsPrecision = true;
long length = 0;
int scale = 0;
checkIsIdentifier();
if (token.namePrefix == null) {
typeNumber = Type.getTypeNr(token.tokenString);
}
if (database.sqlSyntaxOra && !session.isProcessingScript()) {
if (typeNumber == Types.SQL_DATE) {
read();
return Type.SQL_TIMESTAMP_NO_FRACTION;
}
}
if (typeNumber == Integer.MIN_VALUE) {
if (includeUserTypes) {
checkIsSchemaObjectName();
Type type = database.schemaManager.findDomainOrUDT(session,
token.tokenString, token.namePrefix, token.namePrePrefix,
token.namePrePrePrefix);
if (type != null) {
getRecordedToken().setExpression(type);
compileContext.addSchemaObject(type);
read();
return type;
}
}
if (token.namePrefix != null) {
throw Error.error(ErrorCode.X_42509, token.tokenString);
}
if (database.sqlSyntaxOra) {
switch (token.tokenType) {
case Tokens.BINARY_DOUBLE :
case Tokens.BINARY_FLOAT :
read();
return Type.SQL_DOUBLE;
case Tokens.LONG :
read();
if (token.tokenType == Tokens.RAW) {
read();
return Type.getType(Types.SQL_VARBINARY, null,
null,
BlobType.defaultBlobSize, 0);
} else {
readIfThis(Tokens.VARCHAR);
return Type.getType(Types.SQL_VARCHAR, null,
database.collation,
ClobType.defaultClobSize, 0);
}
case Tokens.NUMBER :
read();
if (token.tokenType == Tokens.OPENBRACKET) {
read();
int precision = readInteger();
scale = 0;
if (token.tokenType == Tokens.COMMA) {
read();
scale = readInteger();
}
readThis(Tokens.CLOSEBRACKET);
return Type.getType(Types.SQL_DECIMAL, null, null,
precision, scale);
} else {
return Type.SQL_DECIMAL_DEFAULT;
}
case Tokens.RAW :
typeNumber = Types.SQL_VARBINARY;
break;
case Tokens.VARCHAR2 :
readByteOrChar = true;
enforceSize = false;
typeNumber = Types.SQL_VARCHAR;
break;
case Tokens.NVARCHAR2 :
typeNumber = Types.SQL_VARCHAR;
break;
case Tokens.NCHAR :
typeNumber = Types.SQL_CHAR;
break;
default :
}
}
if (database.sqlSyntaxMss) {
if (Tokens.T_MONEY.equals(token.tokenString)) {
return Type.getType(Types.SQL_DECIMAL, null, null, 18, 4);
} else if (Tokens.T_UNIQUEIDENTIFIER.equals(
token.tokenString)) {
return Type.SQL_GUID;
} else if (Tokens.T_DATETIME2.equals(token.tokenString)) {
typeNumber = Types.SQL_TIMESTAMP;
} else if (Tokens.T_IMAGE.equals(token.tokenString)) {
typeNumber = Types.LONGVARBINARY;
} else if (Tokens.T_NTEXT.equals(token.tokenString)) {
typeNumber = Types.LONGVARCHAR;
}
switch (token.tokenType) {
case Tokens.DATETIMEOFFSET :
typeNumber = Types.SQL_TIMESTAMP_WITH_TIME_ZONE;
break;
case Tokens.TEXT :
typeNumber = Types.LONGVARCHAR;
break;
}
}
if (database.sqlSyntaxPgs) {
switch (token.tokenType) {
case Tokens.TEXT :
typeNumber = Types.LONGVARCHAR;
readByteOrChar = true;
break;
case Tokens.CITEXT :
typeNumber = Types.VARCHAR_IGNORECASE;
break;
default :
if ("BYTEA".equals(token.tokenString)) {
typeNumber = Types.LONGVARBINARY;
} else if ("INT2".equals(token.tokenString)) {
typeNumber = Types.SQL_SMALLINT;
} else if ("INT4".equals(token.tokenString)) {
typeNumber = Types.SQL_INTEGER;
} else if ("INT8".equals(token.tokenString)) {
typeNumber = Types.SQL_BIGINT;
} else if ("REAL".equals(token.tokenString)) {
typeNumber = Types.SQL_DOUBLE;
} else if ("TIMESTAMPTZ".equals(token.tokenString)) {
typeNumber = Types.SQL_TIMESTAMP_WITH_TIME_ZONE;
scale = DTIType.defaultTimestampFractionPrecision;
}
}
}
if (database.sqlSyntaxMys) {
switch (token.tokenType) {
case Tokens.ENUM :
return readMysEnum();
case Tokens.TINYTEXT :
typeNumber = Types.VARCHAR;
acceptsPrecision = false;
break;
case Tokens.TEXT :
typeNumber = Types.LONGVARCHAR;
acceptsPrecision = false;
break;
case Tokens.MEDIUMTEXT :
case Tokens.LONGTEXT :
typeNumber = Types.LONGVARCHAR;
acceptsPrecision = false;
break;
case Tokens.TINYBLOB :
typeNumber = Types.VARBINARY;
acceptsPrecision = false;
break;
case Tokens.MEDIUMBLOB :
case Tokens.LONGBLOB :
typeNumber = Types.LONGVARBINARY;
acceptsPrecision = false;
break;
}
}
if (typeNumber == Integer.MIN_VALUE) {
throw Error.error(ErrorCode.X_42509, token.tokenString);
}
}
read();
switch (typeNumber) {
case Types.SQL_CHAR :
if (token.tokenType == Tokens.VARYING) {
read();
typeNumber = Types.SQL_VARCHAR;
} else if (token.tokenType == Tokens.LARGE) {
read();
readThis(Tokens.OBJECT);
typeNumber = Types.SQL_CLOB;
} else {
if (database.sqlSyntaxOra) {
readByteOrChar = true;
}
}
break;
case Types.SQL_DOUBLE :
if (token.tokenType == Tokens.PRECISION) {
read();
}
break;
case Types.SQL_BINARY :
if (token.tokenType == Tokens.VARYING) {
read();
typeNumber = Types.SQL_VARBINARY;
} else if (token.tokenType == Tokens.LARGE) {
read();
readThis(Tokens.OBJECT);
typeNumber = Types.SQL_BLOB;
}
break;
case Types.SQL_BIT :
if (token.tokenType == Tokens.VARYING) {
read();
typeNumber = Types.SQL_BIT_VARYING;
}
break;
case Types.SQL_INTERVAL :
return readIntervalType(session, false);
default :
}
if (typeNumber == Types.SQL_TIMESTAMP) {
length = DTIType.defaultTimestampFractionPrecision;
}
acceptsPrecision &= Types.acceptsPrecision(typeNumber);
if (acceptsPrecision && enforceSize
&& Types.requiresPrecision(typeNumber)) {
if (token.tokenType != Tokens.OPENBRACKET
&& !session.isProcessingScript()) {
throw Error.error(
ErrorCode.X_42599,
Type.getDefaultType(typeNumber).getNameString());
}
}
if (database.sqlSyntaxMys) {
switch (typeNumber) {
case Types.TINYINT :
case Types.SQL_INTEGER :
case Types.SQL_SMALLINT :
case Types.SQL_BIGINT :
acceptsPrecision = true;
break;
}
}
if (database.sqlSyntaxMss) {
switch (typeNumber) {
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
acceptsPrecision = true;
break;
}
}
if (acceptsPrecision) {
if (token.tokenType == Tokens.OPENBRACKET) {
int multiplier = 1;
read();
switch (token.tokenType) {
case Tokens.X_VALUE :
if (token.dataType.typeCode != Types.SQL_INTEGER
&& token.dataType.typeCode
!= Types.SQL_BIGINT) {
throw unexpectedToken();
}
break;
case Tokens.X_LOB_SIZE :
if (typeNumber == Types.SQL_BLOB
|| typeNumber == Types.SQL_CLOB
|| typeNumber == Types.SQL_VARBINARY
|| typeNumber == Types.SQL_VARCHAR) {
switch (token.lobMultiplierType) {
case Tokens.K :
multiplier = 1024;
break;
case Tokens.M :
multiplier = 1024 * 1024;
break;
case Tokens.G :
multiplier = 1024 * 1024 * 1024;
break;
case Tokens.P :
case Tokens.T :
default :
throw unexpectedToken();
}
break;
} else {
throw unexpectedToken(token.getFullString());
}
case Tokens.MAX :
if (database.sqlSyntaxMss) {
token.tokenValue = Long.valueOf(Integer.MAX_VALUE);
break;
}
throw unexpectedToken();
default :
throw unexpectedToken();
}
hasLength = true;
length = ((Number) token.tokenValue).longValue();
if (length < 0
|| (length == 0
&& !Types.acceptsZeroPrecision(typeNumber))) {
throw Error.error(ErrorCode.X_42592);
}
length *= multiplier;
read();
if (typeNumber == Types.SQL_CHAR
|| typeNumber == Types.SQL_VARCHAR
|| typeNumber == Types.SQL_CLOB) {
if (token.tokenType == Tokens.CHARACTERS) {
read();
} else if (token.tokenType == Tokens.OCTETS) {
read();
}
}
if (Types.acceptsScaleCreateParam(typeNumber)
&& token.tokenType == Tokens.COMMA) {
read();
scale = readInteger();
if (scale < 0) {
if (typeNumber == Types.SQL_DECIMAL
&& database.sqlSyntaxOra) {
//
} else {
throw Error.error(ErrorCode.X_42592);
}
}
if (typeNumber == Types.SQL_DECIMAL && scale > length) {
throw Error.error(ErrorCode.X_42592);
}
hasScale = true;
}
if (readByteOrChar) {
if (!readIfThis(Tokens.CHAR)) {
readIfThis(Tokens.BYTE);
}
}
readThis(Tokens.CLOSEBRACKET);
} else if (typeNumber == Types.SQL_BIT) {
length = 1;
} else if (typeNumber == Types.SQL_BLOB
|| typeNumber == Types.SQL_CLOB) {
length = BlobType.defaultBlobSize;
} else if (enforceSize) {
// BIT is always BIT(1), regardless of sqlEnforceSize
if (typeNumber == Types.SQL_CHAR
|| typeNumber == Types.SQL_BINARY) {
length = 1;
}
}
switch (typeNumber) {
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
case Types.SQL_TIMESTAMP :
case Types.SQL_TIME :
if (length > DTIType.maxFractionPrecision) {
throw Error.error(ErrorCode.X_42592);
}
scale = (int) length;
length = 0;
if (typeNumber == Types.SQL_TIMESTAMP_WITH_TIME_ZONE) {
break;
}
if (token.tokenType == Tokens.WITH) {
read();
readThis(Tokens.TIME);
readThis(Tokens.ZONE);
if (typeNumber == Types.SQL_TIMESTAMP) {
typeNumber = Types.SQL_TIMESTAMP_WITH_TIME_ZONE;
} else {
typeNumber = Types.SQL_TIME_WITH_TIME_ZONE;
}
} else if (token.tokenType == Tokens.WITHOUT) {
read();
readThis(Tokens.TIME);
readThis(Tokens.ZONE);
}
}
}
switch (typeNumber) {
case Types.LONGVARCHAR : {
if (database.sqlLongvarIsLob) {
typeNumber = Types.SQL_CLOB;
length = ClobType.defaultClobSize;
} else {
typeNumber = Types.SQL_VARCHAR;
if (!hasLength) {
length = ClobType.defaultShortClobSize;
}
}
break;
}
case Types.LONGVARBINARY : {
if (database.sqlLongvarIsLob) {
typeNumber = Types.SQL_BLOB;
length = BlobType.defaultBlobSize;
} else {
typeNumber = Types.SQL_VARBINARY;
if (!hasLength) {
length = BlobType.defaultShortBlobSize;
}
}
break;
}
case Types.SQL_CHAR :
if (database.sqlSyntaxDb2) {
if (readIfThis(Tokens.FOR)) {
readThis(Tokens.BIT);
readThis(Tokens.DATA);
typeNumber = Types.SQL_BINARY;
break;
}
}
isCharacter = true;
break;
case Types.SQL_CLOB :
isCharacter = true;
break;
case Types.VARCHAR_IGNORECASE :
typeNumber = Types.SQL_VARCHAR;
isIgnoreCase = true;
// fall through
case Types.SQL_VARCHAR :
if (database.sqlSyntaxDb2) {
if (readIfThis(Tokens.FOR)) {
readThis(Tokens.BIT);
readThis(Tokens.DATA);
typeNumber = Types.SQL_VARBINARY;
if (!hasLength) {
length = 32 * 1024;
}
break;
}
}
isCharacter = true;
if (!hasLength) {
length = 32 * 1024;
}
if (session.isIgnorecase()) {
if (!session.isProcessingScript()) {
isIgnoreCase = true;
}
}
if (length > CharacterType.maxCharPrecision) {
throw Error.error(ErrorCode.X_42592);
}
break;
case Types.SQL_BINARY :
break;
case Types.SQL_VARBINARY :
if (!hasLength) {
length = 32 * 1024;
}
if (length > BinaryType.maxBinaryPrecision) {
throw Error.error(ErrorCode.X_42592);
}
break;
case Types.SQL_DECIMAL :
case Types.SQL_NUMERIC :
if (!hasLength && !hasScale && !enforceSize) {
length = NumberType.defaultNumericPrecision;
scale = NumberType.defaultNumericScale;
}
break;
}
Collation collation = database.collation;
Charset charset = null;
if (isCharacter && allowCollation) {
if (token.tokenType == Tokens.CHARACTER) {
read();
readThis(Tokens.SET);
checkIsSchemaObjectName();
charset =
(Charset) database.schemaManager.getCharacterSet(session,
token.tokenString, token.namePrefix);
read();
}
if (token.tokenType == Tokens.COLLATE) {
read();
checkIsSchemaObjectName();
collation = database.schemaManager.getCollation(session,
token.tokenString, token.namePrefix);
read();
} else if (isIgnoreCase) {
collation = Collation.getUpperCaseCompareCollation(collation);
}
}
Type typeObject = Type.getType(typeNumber, charset, collation, length,
scale);
if (token.tokenType == Tokens.ARRAY) {
if (typeObject.isLobType()) {
throw unexpectedToken();
}
read();
int maxCardinality = ArrayType.defaultArrayCardinality;
if (token.tokenType == Tokens.LEFTBRACKET) {
read();
maxCardinality = readInteger();
if (maxCardinality < 0) {
throw Error.error(ErrorCode.X_42592);
}
readThis(Tokens.RIGHTBRACKET);
}
typeObject = new ArrayType(typeObject, maxCardinality);
}
return typeObject;
}
Type readMysEnum() {
read();
checkIsThis(Tokens.OPENBRACKET);
HsqlName name = database.nameManager.newHsqlName("ENUM", false,
SchemaObject.DOMAIN);
Type t = Type.getType(Types.SQL_VARCHAR, null, null, 32, 0);
t.userTypeModifier = new UserTypeModifier(name, SchemaObject.DOMAIN,
t);
return t;
}
void readSimpleColumnNames(OrderedHashSet columns, RangeVariable rangeVar,
boolean withPrefix) {
while (true) {
ColumnSchema col = readSimpleColumnName(rangeVar, withPrefix);
if (!columns.add(col.getName().name)) {
throw Error.error(ErrorCode.X_42579, col.getName().name);
}
if (readIfThis(Tokens.COMMA)) {
continue;
}
if (token.tokenType == Tokens.CLOSEBRACKET) {
break;
}
throw unexpectedToken();
}
}
void readTargetSpecificationList(OrderedHashSet targets,
RangeVariable[] rangeVars,
LongDeque colIndexList) {
while (true) {
Expression target = XreadTargetSpecification(rangeVars,
colIndexList);
if (!targets.add(target)) {
ColumnSchema col = target.getColumn();
throw Error.error(ErrorCode.X_42579, col.getName().name);
}
if (readIfThis(Tokens.COMMA)) {
continue;
}
if (token.tokenType == Tokens.CLOSEBRACKET) {
break;
}
if (token.tokenType == Tokens.FROM) {
break;
}
throw unexpectedToken();
}
}
/**
* Process a bracketed column list as used in the declaration of SQL
* CONSTRAINTS and return an array containing the indexes of the columns
* within the table.
*
* @param table table that contains the columns
* @param ascOrDesc boolean
* @return array of column indexes
*/
int[] readColumnList(Table table, boolean ascOrDesc) {
OrderedHashSet set = readColumnNames(ascOrDesc);
return table.getColumnIndexes(set);
}
void readSimpleColumnNames(OrderedHashSet columns, Table table,
boolean withPrefix) {
while (true) {
ColumnSchema col = readSimpleColumnName(table, withPrefix);
if (!columns.add(col.getName().name)) {
throw Error.error(ErrorCode.X_42577, col.getName().name);
}
if (readIfThis(Tokens.COMMA)) {
continue;
}
if (token.tokenType == Tokens.CLOSEBRACKET) {
break;
}
throw unexpectedToken();
}
}
HsqlName[] readColumnNames(HsqlName tableName) {
BitMap quotedFlags = new BitMap(0, true);
OrderedHashSet set = readColumnNames(quotedFlags, false);
HsqlName[] colList = new HsqlName[set.size()];
for (int i = 0; i < colList.length; i++) {
String name = (String) set.get(i);
boolean quoted = quotedFlags.isSet(i);
colList[i] = database.nameManager.newHsqlName(tableName.schema,
name, quoted, SchemaObject.COLUMN, tableName);
}
return colList;
}
OrderedHashSet readColumnNames(boolean readAscDesc) {
return readColumnNames(null, readAscDesc);
}
OrderedHashSet readColumnNames(BitMap quotedFlags, boolean readAscDesc) {
readThis(Tokens.OPENBRACKET);
OrderedHashSet set = new OrderedHashSet();
readColumnNameList(set, quotedFlags, readAscDesc);
readThis(Tokens.CLOSEBRACKET);
return set;
}
void readColumnNameList(OrderedHashSet set, BitMap quotedFlags,
boolean readAscDesc) {
int i = 0;
while (true) {
if (session.isProcessingScript()) {
// for old scripts
if (!isSimpleName()) {
token.isDelimitedIdentifier = true;
}
} else {
checkIsSimpleName();
}
if (!set.add(token.tokenString)) {
throw Error.error(ErrorCode.X_42577, token.tokenString);
}
if (quotedFlags != null) {
quotedFlags.setValue(i, isDelimitedIdentifier());
}
read();
i++;
if (readAscDesc) {
if (token.tokenType == Tokens.ASC
|| token.tokenType == Tokens.DESC) {
read();
}
}
if (readIfThis(Tokens.COMMA)) {
continue;
}
break;
}
}
SimpleName[] readColumnNameList(OrderedHashSet set) {
BitMap columnNameQuoted = new BitMap(0, true);
readThis(Tokens.OPENBRACKET);
readColumnNameList(set, columnNameQuoted, false);
readThis(Tokens.CLOSEBRACKET);
SimpleName[] columnNameList = new SimpleName[set.size()];
for (int i = 0; i < set.size(); i++) {
SimpleName name =
HsqlNameManager.getSimpleName((String) set.get(i),
columnNameQuoted.isSet(i));
columnNameList[i] = name;
}
return columnNameList;
}
int XreadUnionType() {
int unionType = QueryExpression.NOUNION;
switch (token.tokenType) {
case Tokens.UNION :
read();
unionType = QueryExpression.UNION;
if (token.tokenType == Tokens.ALL) {
unionType = QueryExpression.UNION_ALL;
read();
} else if (token.tokenType == Tokens.DISTINCT) {
read();
}
break;
case Tokens.INTERSECT :
read();
unionType = QueryExpression.INTERSECT;
if (token.tokenType == Tokens.ALL) {
unionType = QueryExpression.INTERSECT_ALL;
read();
} else if (token.tokenType == Tokens.DISTINCT) {
read();
}
break;
case Tokens.EXCEPT :
case Tokens.MINUS_EXCEPT :
read();
unionType = QueryExpression.EXCEPT;
if (token.tokenType == Tokens.ALL) {
unionType = QueryExpression.EXCEPT_ALL;
read();
} else if (token.tokenType == Tokens.DISTINCT) {
read();
}
break;
default :
break;
}
return unionType;
}
void XreadUnionCorrespondingClause(QueryExpression queryExpression) {
if (token.tokenType == Tokens.CORRESPONDING) {
read();
queryExpression.setUnionCorresoponding();
if (token.tokenType == Tokens.BY) {
read();
OrderedHashSet names = readColumnNames(false);
queryExpression.setUnionCorrespondingColumns(names);
}
}
}
QueryExpression XreadQueryExpression() {
try {
XreadWithClause();
QueryExpression queryExpression = XreadQueryExpressionBody();
SortAndSlice sortAndSlice = XreadOrderByExpression();
if (queryExpression.sortAndSlice == SortAndSlice.noSort) {
queryExpression.addSortAndSlice(sortAndSlice);
} else {
if (queryExpression.sortAndSlice.hasLimit()) {
if (sortAndSlice.hasLimit()) {
throw Error.error(ErrorCode.X_42549);
}
for (int i = 0; i < sortAndSlice.exprList.size(); i++) {
Expression e =
(Expression) sortAndSlice.exprList.get(i);
queryExpression.sortAndSlice.addOrderExpression(e);
}
} else {
if (sortAndSlice != SortAndSlice.noSort) {
queryExpression.addSortAndSlice(sortAndSlice);
}
}
}
return queryExpression;
} finally {
compileContext.unregisterSubqueries();
}
}
void XreadWithClause() {
if (token.tokenType == Tokens.WITH) {
read();
compileContext.unregisterSubqueries();
boolean recursive = readIfThis(Tokens.RECURSIVE);
while (true) {
checkIsSimpleName();
HsqlName[] nameList = null;
HsqlName queryName =
database.nameManager.newHsqlName(token.tokenString,
isDelimitedIdentifier(),
SchemaObject.SUBQUERY);
queryName.schema = SqlInvariants.SYSTEM_SCHEMA_HSQLNAME;
read();
compileContext.registerSubquery(queryName.name);
if (token.tokenType == Tokens.OPENBRACKET) {
nameList = readColumnNames(queryName);
} else if (recursive) {
throw unexpectedTokenRequire(Tokens.T_OPENBRACKET);
}
readThis(Tokens.AS);
readThis(Tokens.OPENBRACKET);
TableDerived td;
td = XreadTableNamedSubqueryBody(queryName, nameList,
recursive
? OpTypes.RECURSIVE_SUBQUERY
: OpTypes.TABLE_SUBQUERY);
if (nameList == null) {
boolean[] cols = td.queryExpression.accessibleColumns;
if (ArrayUtil.countTrueElements(cols) < cols.length) {
throw Error.error(ErrorCode.X_42578);
}
}
readThis(Tokens.CLOSEBRACKET);
if (td.queryExpression != null
&& td.queryExpression.isRecursive()) {
XreadRecursiveFeatures(td);
}
compileContext.registerSubquery(queryName.name, td);
if (token.tokenType == Tokens.COMMA) {
read();
continue;
}
break;
}
}
}
void XreadRecursiveFeatures(TableDerived table) {
RecursiveQuerySettings settings = null;
if (token.tokenType == Tokens.SEARCH) {
read();
settings = new RecursiveQuerySettings();
switch (token.tokenType) {
case Tokens.DEPTH :
read();
settings.searchOrderType =
RecursiveQuerySettings.depthFirst;
break;
case Tokens.BREADTH :
read();
settings.searchOrderType =
RecursiveQuerySettings.breadthFirst;
break;
default :
throw unexpectedTokenRequire("DEPTH or BREADTH");
}
readThis(Tokens.FIRST);
readThis(Tokens.BY);
settings.searchOrderSort = XreadOrderBy();
readThis(Tokens.SET);
checkIsSimpleName();
HsqlName searchOrderName =
database.nameManager.newColumnHsqlName(table.getName(),
token.tokenString, token.isDelimitedIdentifier);
if (table.findColumn(searchOrderName.name) != -1) {
throw Error.error(ErrorCode.X_42578, token.tokenString);
}
read();
settings.searchOrderSetColumn = new ColumnSchema(searchOrderName,
Type.SQL_INTEGER, true, false, null);
}
if (token.tokenType == Tokens.CYCLE) {
read();
if (settings == null) {
settings = new RecursiveQuerySettings();
}
OrderedHashSet set = new OrderedHashSet();
readColumnNameList(set, null, false);
settings.cycleColumnList = table.getColumnIndexes(set);
if (set.size() > 1) {
throw Error.error(ErrorCode.X_42564, token.tokenString);
}
settings.cycleColumnFirst =
table.getColumn(settings.cycleColumnList[0]);
readThis(Tokens.SET);
checkIsSimpleName();
HsqlName cycleName =
database.nameManager.newColumnHsqlName(table.getName(),
token.tokenString, token.isDelimitedIdentifier);
settings.cycleMarkColumn = new ColumnSchema(cycleName,
Type.SQL_CHAR, false, false, null);
if (table.findColumn(cycleName.name) != -1) {
throw Error.error(ErrorCode.X_42578, token.tokenString);
}
read();
readThis(Tokens.TO);
settings.cycleMarkValue = readQuotedString();
if (settings.cycleMarkValue.length() != 1) {
throw unexpectedToken(settings.cycleMarkValue);
}
readThis(Tokens.DEFAULT);
settings.noCycleMarkValue = readQuotedString();
if (settings.noCycleMarkValue.length() != 1) {
throw unexpectedToken(settings.noCycleMarkValue);
}
if (settings.cycleMarkValue.equals(settings.noCycleMarkValue)) {
throw unexpectedToken(settings.cycleMarkValue);
}
if (readIfThis(Tokens.USING)) {
checkIsSimpleName();
HsqlName pathName =
database.nameManager.newColumnHsqlName(table.getName(),
token.tokenString, token.isDelimitedIdentifier);
if (table.findColumn(pathName.name) != -1) {
throw Error.error(ErrorCode.X_42578, token.tokenString);
}
read();
Type arrayType =
new ArrayType(settings.cycleColumnFirst.getDataType(),
ArrayType.defaultArrayCardinality);
settings.cyclePathColumn = new ColumnSchema(pathName,
arrayType, false, false, null);
}
}
table.queryExpression.setRecursiveQuerySettings(settings);
}
QueryExpression XreadQueryExpressionBody() {
QueryExpression queryExpression = XreadQueryTerm();
while (true) {
switch (token.tokenType) {
case Tokens.UNION :
case Tokens.EXCEPT :
case Tokens.MINUS_EXCEPT : {
queryExpression = XreadSetOperation(queryExpression);
break;
}
default : {
return queryExpression;
}
}
}
}
QueryExpression XreadQueryTerm() {
QueryExpression queryExpression = XreadQueryPrimary();
while (true) {
if (token.tokenType == Tokens.INTERSECT) {
queryExpression = XreadSetOperation(queryExpression);
} else {
return queryExpression;
}
}
}
private QueryExpression XreadSetOperation(
QueryExpression queryExpression) {
queryExpression = new QueryExpression(compileContext, queryExpression);
int unionType = XreadUnionType();
XreadUnionCorrespondingClause(queryExpression);
QueryExpression rightQueryExpression = XreadQueryTerm();
queryExpression.addUnion(rightQueryExpression, unionType);
return queryExpression;
}
QueryExpression XreadQueryPrimary() {
switch (token.tokenType) {
case Tokens.TABLE :
case Tokens.VALUES :
case Tokens.SELECT : {
QuerySpecification select = XreadSimpleTable();
return select;
}
case Tokens.OPENBRACKET : {
read();
QueryExpression queryExpression = XreadQueryExpressionBody();
SortAndSlice sortAndSlice = XreadOrderByExpression();
readThis(Tokens.CLOSEBRACKET);
if (queryExpression.sortAndSlice == SortAndSlice.noSort) {
queryExpression.addSortAndSlice(sortAndSlice);
} else {
if (queryExpression.sortAndSlice.hasLimit()) {
if (sortAndSlice.hasLimit()) {
throw Error.error(ErrorCode.X_42549);
}
for (int i = 0; i < sortAndSlice.exprList.size();
i++) {
Expression e =
(Expression) sortAndSlice.exprList.get(i);
queryExpression.sortAndSlice.addOrderExpression(e);
}
} else {
if (sortAndSlice != SortAndSlice.noSort) {
queryExpression.addSortAndSlice(sortAndSlice);
}
}
}
return queryExpression;
}
default : {
throw unexpectedToken();
}
}
}
QuerySpecification XreadSimpleTable() {
QuerySpecification select;
switch (token.tokenType) {
case Tokens.TABLE : {
read();
Table table = readNamedSubqueryOrNull();
if (table == null) {
table = readTableName(true);
}
if (table.isView()) {
table = ((View) table).newDerivedTable(session,
compileContext);
}
select = new QuerySpecification(session, table,
compileContext, false);
break;
}
case Tokens.VALUES : {
read();
TableDerived td = XreadRowValueExpressionList();
select = new QuerySpecification(session, td, compileContext,
true);
break;
}
case Tokens.SELECT : {
select = XreadQuerySpecification();
break;
}
default : {
throw unexpectedToken();
}
}
return select;
}
QuerySpecification XreadQuerySpecification() {
QuerySpecification select = XreadSelect();
if (!select.isValueList
&& select.getCurrentRangeVariableCount() == 0) {
XreadTableExpression(select);
}
return select;
}
void XreadTableExpression(QuerySpecification select) {
XreadFromClause(select);
readWhereGroupHaving(select);
}
QuerySpecification XreadSelect() {
QuerySpecification select = new QuerySpecification(compileContext);
readThis(Tokens.SELECT);
if (token.tokenType == Tokens.TOP || token.tokenType == Tokens.LIMIT) {
SortAndSlice sortAndSlice = XreadTopOrLimit();
if (sortAndSlice != null) {
select.addSortAndSlice(sortAndSlice);
}
}
if (token.tokenType == Tokens.DISTINCT) {
select.setDistinctSelect();
read();
} else if (token.tokenType == Tokens.ALL) {
read();
}
while (true) {
Expression e = XreadValueExpression();
if (token.tokenType == Tokens.AS) {
if (e.getType() == OpTypes.MULTICOLUMN) {
throw unexpectedToken();
}
read();
checkIsNonCoreReservedIdentifier();
}
if (isNonCoreReservedIdentifier()) {
if (e.getType() == OpTypes.MULTICOLUMN) {
throw unexpectedToken();
}
e.setAlias(HsqlNameManager.getSimpleName(token.tokenString,
isDelimitedIdentifier()));
read();
}
select.addSelectColumnExpression(e);
if (token.tokenType == Tokens.FROM) {
break;
}
if (token.tokenType == Tokens.INTO) {
break;
}
if (readIfThis(Tokens.COMMA)) {
continue;
}
if (token.tokenType == Tokens.CLOSEBRACKET
|| token.tokenType == Tokens.X_ENDPARSE
|| token.tokenType == Tokens.SEMICOLON) {
if (database.sqlSyntaxMss || database.sqlSyntaxMys
|| database.sqlSyntaxPgs) {
RangeVariable range =
new RangeVariable(database.schemaManager.dualTable,
null, null, null, compileContext);
select.addRangeVariable(session, range);
return select;
}
}
throw unexpectedToken();
}
return select;
}
void XreadFromClause(QuerySpecification select) {
readThis(Tokens.FROM);
while (true) {
XreadTableReference(select);
if (readIfThis(Tokens.COMMA)) {
// set last range as boundary
continue;
}
break;
}
}
void XreadTableReference(QuerySpecification select) {
boolean natural = false;
RangeVariable leftRange = readTableOrSubquery();
select.addRangeVariable(session, leftRange);
while (true) {
int type;
boolean left = false;
boolean right = false;
boolean end = false;
type = token.tokenType;
switch (token.tokenType) {
case Tokens.NATURAL :
if (natural) {
throw unexpectedToken();
}
read();
natural = true;
continue;
case Tokens.INNER :
read();
readThis(Tokens.JOIN);
break;
case Tokens.CROSS :
if (natural) {
throw unexpectedToken();
}
read();
readThis(Tokens.JOIN);
break;
case Tokens.UNION :
if (natural) {
throw unexpectedToken();
}
int position = getPosition();
read();
if (token.tokenType == Tokens.JOIN) {
read();
left = true;
right = true;
} else {
rewind(position);
end = true;
}
break;
case Tokens.LEFT :
read();
readIfThis(Tokens.OUTER);
readThis(Tokens.JOIN);
left = true;
break;
case Tokens.RIGHT :
read();
readIfThis(Tokens.OUTER);
readThis(Tokens.JOIN);
right = true;
break;
case Tokens.FULL :
read();
readIfThis(Tokens.OUTER);
readThis(Tokens.JOIN);
left = true;
right = true;
break;
case Tokens.JOIN :
read();
type = Tokens.INNER;
break;
case Tokens.COMMA :
default :
if (natural) {
throw unexpectedToken();
}
end = true;
break;
}
if (end) {
break;
}
RangeVariable rightRange = readTableOrSubquery();
Expression condition = null;
rightRange.setJoinType(left, right);
switch (type) {
case Tokens.CROSS :
select.addRangeVariable(session, rightRange);
break;
case Tokens.UNION :
condition = Expression.EXPR_FALSE;
rightRange.addJoinCondition(condition);
select.addRangeVariable(session, rightRange);
break;
case Tokens.LEFT :
case Tokens.RIGHT :
case Tokens.INNER :
case Tokens.FULL : {
boolean using = token.tokenType == Tokens.USING;
if (natural || using) {
leftRange.resolveRangeTable(
session, RangeGroup.emptyGroup,
compileContext.getOuterRanges());
rightRange.resolveRangeTable(
session, RangeGroup.emptyGroup,
compileContext.getOuterRanges());
}
if (natural) {
OrderedHashSet columns =
rightRange.getUniqueColumnNameSet();
condition = select.getEquiJoinExpressions(columns,
rightRange, false);
rightRange.addJoinCondition(condition);
select.addRangeVariable(session, rightRange);
} else if (using) {
read();
OrderedHashSet columns = new OrderedHashSet();
readThis(Tokens.OPENBRACKET);
readSimpleColumnNames(columns, rightRange, false);
readThis(Tokens.CLOSEBRACKET);
condition = select.getEquiJoinExpressions(columns,
rightRange, true);
rightRange.addJoinCondition(condition);
select.addRangeVariable(session, rightRange);
} else if (token.tokenType == Tokens.ON) {
read();
condition = XreadBooleanValueExpression();
rightRange.addJoinCondition(condition);
select.addRangeVariable(session, rightRange);
} else {
throw unexpectedToken();
}
break;
}
}
natural = false;
}
}
Expression getRowExpression(OrderedHashSet columnNames) {
Expression[] elements = new Expression[columnNames.size()];
for (int i = 0; i < elements.length; i++) {
String name = (String) columnNames.get(i);
elements[i] = new ExpressionColumn(null, null, name);
}
return new Expression(OpTypes.ROW, elements);
}
void readWhereGroupHaving(QuerySpecification select) {
// where
if (token.tokenType == Tokens.WHERE) {
read();
Expression e = XreadBooleanValueExpression();
select.addQueryCondition(e);
}
// group by
if (token.tokenType == Tokens.GROUP) {
read();
readThis(Tokens.BY);
if (readIfThis(Tokens.DISTINCT)) {
select.setDistinctGroups();
} else {
readIfThis(Tokens.ALL);
}
HsqlArrayList expressions = new HsqlArrayList();
while (true) {
Expression e = XreadGroupByExpressionPrimary();
expressions.add(e);
if (token.tokenType == Tokens.COMMA) {
read();
continue;
}
break;
}
Expression[] exprArray = new Expression[expressions.size()];
expressions.toArray(exprArray);
select.addGroupingSets(exprArray);
}
// having
if (token.tokenType == Tokens.HAVING) {
read();
Expression e = XreadBooleanValueExpression();
select.addHavingExpression(e);
}
}
SortAndSlice XreadOrderByExpression() {
SortAndSlice sortAndSlice = null;
if (token.tokenType == Tokens.ORDER) {
read();
readThis(Tokens.BY);
sortAndSlice = XreadOrderBy();
}
if (token.tokenType == Tokens.LIMIT || token.tokenType == Tokens.FETCH
|| token.tokenType == Tokens.OFFSET) {
if (sortAndSlice == null) {
sortAndSlice = new SortAndSlice();
}
XreadLimit(sortAndSlice);
}
return sortAndSlice == null ? SortAndSlice.noSort
: sortAndSlice;
}
private SortAndSlice XreadTopOrLimit() {
Expression e1 = null;
Expression e2 = null;
if (token.tokenType == Tokens.LIMIT) {
int position = getPosition();
read();
e1 = XreadSimpleValueSpecificationOrNull();
if (e1 == null) {
rewind(position);
return null;
}
// optional comma
readIfThis(Tokens.COMMA);
e2 = XreadSimpleValueSpecificationOrNull();
if (e2 == null) {
throw Error.error(ErrorCode.X_42563,
ErrorCode.M_INVALID_LIMIT);
}
} else if (token.tokenType == Tokens.TOP) {
int position = getPosition();
read();
e2 = XreadSimpleValueSpecificationOrNull();
if (e2 == null) {
rewind(position);
return null;
}
e1 = new ExpressionValue(ValuePool.INTEGER_0, Type.SQL_INTEGER);
} else {
throw unexpectedToken();
}
boolean valid = true;
if (e1.isUnresolvedParam()) {
e1.setDataType(session, Type.SQL_INTEGER);
} else if (e1.opType == OpTypes.VALUE) {
valid = (e1.getDataType().typeCode == Types.SQL_INTEGER
&& ((Integer) e1.getValue(null)).intValue() >= 0);
} else {
throw Error.error(ErrorCode.X_42563, ErrorCode.M_INVALID_LIMIT);
}
if (e2.isUnresolvedParam()) {
e2.setDataType(session, Type.SQL_INTEGER);
} else if (e2.opType == OpTypes.VALUE) {
valid &= (e2.getDataType().typeCode == Types.SQL_INTEGER
&& ((Integer) e2.getValue(null)).intValue() >= 0);
} else {
throw Error.error(ErrorCode.X_42563, ErrorCode.M_INVALID_LIMIT);
}
if (valid) {
SortAndSlice sortAndSlice = new SortAndSlice();
sortAndSlice.addLimitCondition(new ExpressionOp(OpTypes.LIMIT, e1,
e2));
return sortAndSlice;
}
throw Error.error(ErrorCode.X_42563, ErrorCode.M_INVALID_LIMIT);
}
private void XreadLimit(SortAndSlice sortAndSlice) {
Expression e1 = null;
Expression e2 = null;
if (token.tokenType == Tokens.OFFSET) {
read();
e1 = XreadSimpleValueSpecificationOrNull();
if (e1 == null) {
throw Error.error(ErrorCode.X_42563,
ErrorCode.M_INVALID_LIMIT);
}
if (token.tokenType == Tokens.ROW
|| token.tokenType == Tokens.ROWS) {
read();
}
}
if (token.tokenType == Tokens.LIMIT) {
read();
e2 = XreadSimpleValueSpecificationOrNull();
if (e2 == null) {
throw Error.error(ErrorCode.X_42563,
ErrorCode.M_INVALID_LIMIT);
}
if (e1 == null) {
if (token.tokenType == Tokens.COMMA) {
read();
e1 = e2;
e2 = XreadSimpleValueSpecificationOrNull();
} else if (token.tokenType == Tokens.OFFSET) {
read();
e1 = XreadSimpleValueSpecificationOrNull();
}
}
if (database.sqlSyntaxPgs || database.sqlSyntaxMys) {
sortAndSlice.setZeroLimitIsZero();
}
} else if (token.tokenType == Tokens.FETCH) {
read();
boolean first = false;
if (token.tokenType == Tokens.FIRST
|| token.tokenType == Tokens.NEXT) {
first = true;
read();
}
e2 = XreadSimpleValueSpecificationOrNull();
if (e2 == null) {
if (!first) {
throw super.unexpectedTokenRequire(Tokens.T_FIRST);
}
e2 = new ExpressionValue(ValuePool.INTEGER_1,
Type.SQL_INTEGER);
}
if (token.tokenType == Tokens.ROW
|| token.tokenType == Tokens.ROWS) {
read();
}
readThis(Tokens.ONLY);
sortAndSlice.setStrictLimit();
}
if (sortAndSlice.hasOrder() && token.tokenType == Tokens.USING) {
read();
readThis(Tokens.INDEX);
sortAndSlice.setUsingIndex();
}
if (e1 == null) {
e1 = new ExpressionValue(ValuePool.INTEGER_0, Type.SQL_INTEGER);
}
boolean valid = true;
if (e1.isUnresolvedParam()) {
e1.setDataType(session, Type.SQL_INTEGER);
}
if (e2 != null) {
if (e2.isUnresolvedParam()) {
e2.setDataType(session, Type.SQL_INTEGER);
}
}
if (valid) {
sortAndSlice.addLimitCondition(new ExpressionOp(OpTypes.LIMIT, e1,
e2));
return;
}
throw Error.error(ErrorCode.X_42563, ErrorCode.M_INVALID_LIMIT);
}
private SortAndSlice XreadOrderBy() {
SortAndSlice sortAndSlice = new SortAndSlice();
while (true) {
Expression e;
ExpressionOrderBy o;
boolean isDesc = false;
boolean nullsLast = false;
e = XreadValueExpression();
o = new ExpressionOrderBy(e);
if (token.tokenType == Tokens.DESC) {
o.setDescending();
isDesc = true;
read();
} else if (token.tokenType == Tokens.ASC) {
read();
}
if (database.sqlNullsOrder) {
nullsLast = !database.sqlNullsFirst;
} else {
nullsLast = database.sqlNullsFirst == isDesc;
}
o.setNullsLast(nullsLast);
if (token.tokenType == Tokens.NULLS) {
read();
if (token.tokenType == Tokens.FIRST) {
read();
o.setNullsLast(false);
} else if (token.tokenType == Tokens.LAST) {
read();
o.setNullsLast(true);
} else {
throw unexpectedToken();
}
}
sortAndSlice.addOrderExpression(o);
if (token.tokenType == Tokens.COMMA) {
read();
continue;
}
break;
}
return sortAndSlice;
}
protected RangeVariable readRangeVariableForDataChange(int operation) {
Table table = readTableName(true);
ExpressionPeriodOp appPeriodSpec =
XreadQueryApplicationPeriodSpecOrNull(table);
SimpleName alias = null;
if (appPeriodSpec != null) {
throw Error.error(ErrorCode.X_0A501);
}
if (operation != StatementTypes.TRUNCATE) {
switch (token.tokenType) {
case Tokens.OVERRIDING :
break;
case Tokens.AS :
read();
checkIsNonCoreReservedIdentifier();
// fall through
default :
if (isNonCoreReservedIdentifier()) {
if (!database.sqlSyntaxMys
|| operation != StatementTypes.INSERT) {
alias = HsqlNameManager.getSimpleName(
token.tokenString, isDelimitedIdentifier());
read();
}
}
}
if (alias == null && lastSynonym != null) {
alias =
HsqlNameManager.getSimpleName(lastSynonym.name,
lastSynonym.isNameQuoted);
}
}
if (table.isView) {
switch (operation) {
case StatementTypes.MERGE :
if (table.isTriggerUpdatable()
&& table.isTriggerInsertable()) {
break;
}
if (table.isTriggerUpdatable()
|| table.isTriggerInsertable()) {
// all or nothing
} else if (table.isUpdatable() && table.isInsertable()) {
break;
}
throw Error.error(ErrorCode.X_42545);
case StatementTypes.UPDATE_WHERE :
if (table.isTriggerUpdatable()) {
break;
}
if (table.isUpdatable()) {
break;
}
throw Error.error(ErrorCode.X_42545);
case StatementTypes.DELETE_WHERE :
if (table.isTriggerDeletable()) {
break;
}
if (table.isUpdatable()) {
break;
}
throw Error.error(ErrorCode.X_42545);
case StatementTypes.INSERT :
if (table.isTriggerInsertable()) {
break;
}
if (table.isInsertable()) {
break;
}
if (session.isProcessingScript()) {
break;
}
throw Error.error(ErrorCode.X_42545);
case StatementTypes.TRUNCATE :
throw Error.error(ErrorCode.X_42545);
}
table = ((View) table).newDerivedTable(session, compileContext);
}
RangeVariable range = new RangeVariable(table, alias, null, null,
compileContext);
if (table.isSystemVersioned()) {
ExpressionPeriodOp sysPeriodSpec = new ExpressionPeriodOp();
sysPeriodSpec.setSystemRangeVariable(session,
RangeGroup.emptyArray, range);
range.setSystemPeriodCondition(sysPeriodSpec);
}
return range;
}
protected Table readNamedSubqueryOrNull() {
if (!isSimpleName()) {
return null;
}
TableDerived td = compileContext.getNamedSubQuery(token.tokenString);
if (td == null) {
return null;
}
read();
if (td.isRecompiled()) {
td = td.newDerivedTable(session, compileContext);
}
return td;
}
/**
* Creates a RangeVariable from the parse context.
*/
protected RangeVariable readTableOrSubquery() {
Table table = null;
SimpleName alias = null;
SimpleName[] columnNameList = null;
OrderedHashSet columnList = null;
ExpressionPeriodOp sysPeriodSpec = null;
boolean joinedTable = false;
boolean isLateral = false;
boolean isTableName = false;
switch (token.tokenType) {
case Tokens.OPENBRACKET : {
table = XreadTableSubqueryOrNull(false);
if (table == null) {
table = XreadJoinedTableAsSubqueryOrNull();
if (table == null) {
table = XreadTableSubqueryOrNull(true);
if (table == null) {
throw unexpectedToken();
}
break;
}
joinedTable = true;
}
break;
}
case Tokens.UNNEST : {
Expression e =
XreadCollectionDerivedTable(OpTypes.TABLE_SUBQUERY);
table = e.getTable();
isLateral = true;
break;
}
case Tokens.LATERAL : {
Expression e = XreadLateralDerivedTable();
table = e.getTable();
isLateral = true;
break;
}
case Tokens.TABLE : {
Expression e = XreadTableFunctionDerivedTable();
table = e.getTable();
isLateral = true;
break;
}
default : {
table = readNamedSubqueryOrNull();
if (table == null) {
table = readTableName(true);
isTableName = true;
// attach to range variable below
sysPeriodSpec = XreadQuerySystemPeriodSpecOrNull(table);
}
if (table.isView()) {
table = ((View) table).newDerivedTable(session,
compileContext);
}
}
}
boolean hasAs = false;
if (token.tokenType == Tokens.AS) {
read();
checkIsNonCoreReservedIdentifier();
hasAs = true;
}
if (isNonCoreReservedIdentifier()) {
boolean limit = token.tokenType == Tokens.LIMIT
|| token.tokenType == Tokens.OFFSET
|| token.tokenType == Tokens.FETCH;
boolean minus = token.tokenType == Tokens.MINUS_EXCEPT;
int position = getPosition();
alias = HsqlNameManager.getSimpleName(token.tokenString,
isDelimitedIdentifier());
read();
if (token.tokenType == Tokens.OPENBRACKET) {
columnList = new OrderedHashSet();
columnNameList = readColumnNameList(columnList);
} else if (!hasAs && limit) {
if (token.tokenType == Tokens.COLON
|| token.tokenType == Tokens.QUESTION
|| token.tokenType == Tokens.X_VALUE) {
alias = null;
rewind(position);
}
} else if (!hasAs && minus) {
rewind(position);
}
}
if (isTableName && alias == null && lastSynonym != null) {
alias = HsqlNameManager.getSimpleName(lastSynonym.name,
lastSynonym.isNameQuoted);
}
if (database.sqlSyntaxMss) {
if (readIfThis(Tokens.WITH)) {
readNestedParenthesisedTokens();
}
}
RangeVariable range;
if (joinedTable) {
range = new RangeVariableJoined(table, alias, columnList,
columnNameList, compileContext);
} else {
range = new RangeVariable(table, alias, columnList,
columnNameList, compileContext);
if (sysPeriodSpec != null) {
RangeGroup[] ranges = compileContext.getOuterRanges();
sysPeriodSpec.setSystemRangeVariable(session, ranges, range);
range.setSystemPeriodCondition(sysPeriodSpec);
}
}
if (isLateral) {
range.isLateral = true;
}
return range;
}
private Expression readAggregateFunctionOrNull() {
int position = getPosition();
int tokenT = token.tokenType;
Expression expr;
read();
if (token.tokenType != Tokens.OPENBRACKET) {
rewind(position);
return null;
}
readThis(Tokens.OPENBRACKET);
expr = readAggregateExpression(tokenT);
readThis(Tokens.CLOSEBRACKET);
readFilterClause(expr);
return expr;
}
private void readFilterClause(Expression e) {
Expression condition = XreadFilterExpressionOrNull();
if (condition != null) {
e.setCondition(condition);
}
}
Expression XreadFilterExpressionOrNull() {
int position = getPosition();
Expression condition = null;
if (token.tokenType == Tokens.FILTER) {
read();
if (token.tokenType != Tokens.OPENBRACKET) {
rewind(position);
return null;
}
readThis(Tokens.OPENBRACKET);
readThis(Tokens.WHERE);
condition = XreadBooleanValueExpression();
readThis(Tokens.CLOSEBRACKET);
}
return condition;
}
private Expression readAggregateExpression(int tokenT) {
int type = ParserDQL.getExpressionType(tokenT);
boolean distinct = false;
boolean all = false;
SortAndSlice sort = null;
String separator = null;
if (token.tokenType == Tokens.DISTINCT) {
distinct = true;
read();
} else if (token.tokenType == Tokens.ALL) {
all = true;
read();
}
int position = getPosition();
Expression e = XreadValueExpression();
switch (type) {
case OpTypes.COUNT :
if (e.getType() == OpTypes.MULTICOLUMN) {
if (((ExpressionColumn) e).tableName != null) {
throw unexpectedToken();
}
if (all || distinct) {
throw unexpectedToken();
}
e.opType = OpTypes.ASTERISK;
} else {
if (token.tokenType == Tokens.COMMA) {
rewind(position);
e = XreadRowElementList(false);
}
}
break;
case OpTypes.STDDEV_POP :
case OpTypes.STDDEV_SAMP :
case OpTypes.VAR_POP :
case OpTypes.VAR_SAMP :
if (all || distinct) {
throw unexpectedToken(all ? Tokens.T_ALL
: Tokens.T_DISTINCT);
}
break;
case OpTypes.ARRAY_AGG :
case OpTypes.GROUP_CONCAT : {
if (token.tokenType == Tokens.ORDER) {
read();
readThis(Tokens.BY);
sort = XreadOrderBy();
}
if (type == OpTypes.GROUP_CONCAT) {
if (token.tokenType == Tokens.SEPARATOR) {
read();
checkIsQuotedString();
separator = (String) token.tokenValue;
read();
}
}
return new ExpressionArrayAggregate(type, distinct, e, sort,
separator);
}
case OpTypes.STRING_AGG : {
readThis(Tokens.COMMA);
checkIsQuotedString();
separator = (String) token.tokenValue;
read();
if (token.tokenType == Tokens.ORDER) {
read();
readThis(Tokens.BY);
sort = XreadOrderBy();
}
return new ExpressionArrayAggregate(OpTypes.GROUP_CONCAT,
distinct, e, sort,
separator);
}
case OpTypes.MEDIAN : {
return new ExpressionArrayAggregate(type, distinct, e, sort,
separator);
}
default :
if (e.getType() == OpTypes.MULTICOLUMN
|| e.getType() == OpTypes.ASTERISK) {
throw unexpectedToken(Tokens.T_ASTERISK);
}
}
Expression aggregateExp = new ExpressionAggregate(type, distinct, e);
return aggregateExp;
}
//--------------------------------------
// returns null
// := |
Expression XreadValueSpecificationOrNull() {
Expression e = null;
boolean minus = false;
switch (token.tokenType) {
case Tokens.PLUS_OP :
read();
break;
case Tokens.MINUS_OP :
read();
minus = true;
break;
default :
}
e = XreadUnsignedValueSpecificationOrNull();
if (e == null) {
return null;
}
if (minus) {
e = new ExpressionArithmetic(OpTypes.NEGATE, e);
}
return e;
}
// returns null
// |
Expression XreadUnsignedValueSpecificationOrNull() {
Expression e;
switch (token.tokenType) {
case Tokens.TRUE :
read();
return new ExpressionBoolean(true);
case Tokens.FALSE :
read();
return new ExpressionBoolean(false);
case Tokens.DEFAULT :
if (compileContext.contextuallyTypedExpression) {
read();
e = new ExpressionColumn(OpTypes.DEFAULT);
return e;
}
break;
case Tokens.VALUES :
if (compileContext.onDuplicateTypedExpression) {
read();
readThis(Tokens.OPENBRACKET);
checkIsSimpleName();
e = new ExpressionColumn(token.tokenString);
read();
readThis(Tokens.CLOSEBRACKET);
return e;
}
break;
case Tokens.NULL :
e = new ExpressionValue(null, null);
read();
return e;
case Tokens.X_VALUE :
e = new ExpressionValue(token.tokenValue, token.dataType);
read();
return e;
case Tokens.X_DELIMITED_IDENTIFIER :
case Tokens.X_IDENTIFIER :
if (!token.isHostParameter) {
return null;
}
return null;
case Tokens.COLON :
case Tokens.QUESTION :
return XreadDynamicParameterOrNull();
case Tokens.COLLATION :
return XreadCurrentCollationSpec();
case Tokens.VALUE :
case Tokens.CURRENT_CATALOG :
case Tokens.CURRENT_DEFAULT_TRANSFORM_GROUP :
case Tokens.CURRENT_PATH :
case Tokens.CURRENT_ROLE :
case Tokens.CURRENT_SCHEMA :
case Tokens.CURRENT_TRANSFORM_GROUP_FOR_TYPE :
case Tokens.CURRENT_USER :
case Tokens.SESSION_USER :
case Tokens.SYSTEM_USER :
case Tokens.USER :
FunctionSQL function =
FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
if (function == null) {
return null;
}
return readSQLFunction(function);
// read SQL parameter reference
}
return null;
}
Expression XreadDynamicParameterOrNull() {
switch (token.tokenType) {
case Tokens.COLON :
read();
if (isIntegral()) {
int pos = readInteger();
ExpressionColumn p =
new ExpressionColumn(OpTypes.DYNAMIC_PARAM, pos);
compileContext.addParameter(p, getPosition());
return p;
} else if (isUndelimitedSimpleName()) {
int pos = compileContext.parameters.size();
ExpressionColumn p =
new ExpressionColumn(OpTypes.DYNAMIC_PARAM, pos);
compileContext.addParameter(p, getPosition());
Token newToken = new Token();
newToken.tokenType = Tokens.X_VALUE;
newToken.dataType = Type.SQL_INTEGER;
newToken.tokenString = String.valueOf(p.parameterIndex);
replaceToken(newToken, null);
read();
return p;
} else {
throw unexpectedToken(Tokens.T_COLON);
}
case Tokens.QUESTION :
int pos = compileContext.parameters.size();
ExpressionColumn p =
new ExpressionColumn(OpTypes.DYNAMIC_PARAM, pos);
compileContext.addParameter(p, getPosition());
Token changedToken = new Token();
changedToken.tokenType = Tokens.COLON;
changedToken.tokenString = Tokens.T_COLON;
Token newToken = new Token();
newToken.tokenType = Tokens.X_VALUE;
newToken.dataType = Type.SQL_INTEGER;
newToken.tokenValue = Integer.valueOf(p.parameterIndex);
newToken.tokenString = String.valueOf(p.parameterIndex);
replaceToken(changedToken, newToken);
read();
return p;
default :
return null;
}
}
// | |
Expression XreadSimpleValueSpecificationOrNull() {
Expression e;
switch (token.tokenType) {
case Tokens.X_VALUE :
e = new ExpressionValue(token.tokenValue, token.dataType);
read();
return e;
case Tokens.COLON :
case Tokens.QUESTION :
return XreadDynamicParameterOrNull();
case Tokens.X_IDENTIFIER :
case Tokens.X_DELIMITED_IDENTIFIER :
checkValidCatalogName(token.namePrePrePrefix);
e = new ExpressionColumn(token.namePrePrefix,
token.namePrefix, token.tokenString);
read();
return e;
default :
return null;
}
}
// combined and
// exclusively called
// needed for predicate
Expression XreadAllTypesValueExpressionPrimary(boolean isBoolean) {
Expression e = null;
int position = getPosition();
switch (token.tokenType) {
case Tokens.EXISTS :
case Tokens.UNIQUE :
if (isBoolean) {
return XreadPredicate();
}
break;
case Tokens.PERIOD :
if (isBoolean) {
break;
}
read();
if (readIfThis(Tokens.OPENBRACKET)) {
e = XreadRowElementList(true);
if (e.nodes.length != 2) {
throw Error.error(ErrorCode.X_42564);
}
e = new ExpressionPeriod(e);
readThis(Tokens.CLOSEBRACKET);
} else {
rewind(position);
e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
}
}
break;
case Tokens.ROW :
if (isBoolean) {
break;
}
read();
readThis(Tokens.OPENBRACKET);
e = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
break;
default :
e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
}
}
if (e == null) {
if (token.tokenType == Tokens.ROW) {
read();
checkIsThis(Tokens.OPENBRACKET);
} else if (token.tokenType == Tokens.PERIOD) {
read();
if (readIfThis(Tokens.OPENBRACKET)) {
e = XreadRowElementList(true);
if (e.nodes.length != 2) {
throw Error.error(ErrorCode.X_42564);
}
e = new ExpressionPeriod(e);
readThis(Tokens.CLOSEBRACKET);
} else {
rewind(position);
e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
}
}
}
if (token.tokenType == Tokens.OPENBRACKET) {
read();
e = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
}
}
if (isBoolean && e != null) {
e = XreadPredicateRightPart(e);
}
return e;
}
// doesn't return null
// ::=
// |
Expression XreadValueExpressionPrimary() {
Expression e;
e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
return e;
}
if (token.tokenType == Tokens.OPENBRACKET) {
read();
e = XreadValueExpression();
readThis(Tokens.CLOSEBRACKET);
} else {
return null;
}
return e;
}
// returns null
// :== this
// :== this |
Expression XreadSimpleValueExpressionPrimary() {
Expression e;
e = XreadUnsignedValueSpecificationOrNull();
if (e != null) {
return e;
}
int position = getPosition();
switch (token.tokenType) {
case Tokens.OPENBRACKET :
read();
int subqueryPosition = getPosition();
readOpenBrackets();
switch (token.tokenType) {
case Tokens.WITH :
case Tokens.TABLE :
case Tokens.VALUES :
case Tokens.SELECT :
TableDerived td = null;
rewind(subqueryPosition);
try {
td = XreadSubqueryTableBody(
OpTypes.SCALAR_SUBQUERY);
readThis(Tokens.CLOSEBRACKET);
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError == null
|| lastError.getLevel() < ex.getLevel()) {
lastError = ex;
}
rewind(position);
return null;
}
if (td.queryExpression != null) {
if (td.queryExpression.isSingleColumn()) {
e = new Expression(OpTypes.SCALAR_SUBQUERY,
td);
} else {
e = new Expression(OpTypes.ROW_SUBQUERY, td);
}
}
if (e != null) {
return e;
}
rewind(position);
return null;
default :
rewind(position);
return null;
}
case Tokens.ASTERISK :
e = new ExpressionColumn(token.namePrePrefix,
token.namePrefix);
getRecordedToken().setExpression(e);
read();
return e;
case Tokens.LEAST : {
e = readLeastExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.GREATEST : {
e = readGreatestExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.DECODE : {
e = readDecodeExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.CONCAT_WORD : {
e = readConcatExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.CONCAT_WS : {
e = readConcatSeparatorExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.IF :
case Tokens.CASEWHEN : {
e = readCaseWhenExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.CASE :
return readCaseExpression();
case Tokens.NULLIF :
return readNullIfExpression();
case Tokens.COALESCE :
return readCoalesceExpression();
case Tokens.IFNULL :
case Tokens.ISNULL : {
e = readIfNullExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.NVL2 : {
e = readIfNull2ExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.CAST :
e = readCastExpression();
if (e != null) {
return e;
}
break;
case Tokens.CONVERT : {
e = readConvertExpressionOrNull();
if (e != null) {
return e;
}
break;
}
case Tokens.DATE :
case Tokens.TIME :
case Tokens.TIMESTAMP :
case Tokens.INTERVAL :
e = readDateTimeIntervalLiteral(session);
if (e != null) {
return e;
}
break;
case Tokens.ARRAY :
return readCollection(OpTypes.ARRAY);
case Tokens.COUNT :
case Tokens.AVG :
case Tokens.MAX :
case Tokens.MIN :
case Tokens.SUM :
case Tokens.ANY :
case Tokens.SOME :
case Tokens.EVERY :
case Tokens.STDDEV_POP :
case Tokens.STDDEV_SAMP :
case Tokens.VAR_POP :
case Tokens.VAR_SAMP :
case Tokens.ARRAY_AGG :
case Tokens.GROUP_CONCAT :
case Tokens.STRING_AGG :
case Tokens.MEDIAN :
e = readAggregateFunctionOrNull(); // general set function
if (e != null) {
return e;
}
break;
case Tokens.NEXT : {
e = readSequenceExpressionOrNull(OpTypes.SEQUENCE);
if (e != null) {
return e;
}
break;
}
case Tokens.PREVVAL :
case Tokens.CURRENT : {
e = readSequenceExpressionOrNull(OpTypes.SEQUENCE_CURRENT);
if (e != null) {
return e;
}
break;
}
case Tokens.CURRVAL : {
if (database.sqlSyntaxPgs) {
read();
readThis(Tokens.OPENBRACKET);
String spec = readQuotedString();
Scanner scanner = session.getScanner();
scanner.reset(session, spec);
scanner.scanNext();
String schemaName =
session.getSchemaName(scanner.token.namePrefix);
NumberSequence sequence =
database.schemaManager.getSequence(
scanner.token.tokenString, schemaName, true);
e = new ExpressionColumn(sequence,
OpTypes.SEQUENCE_CURRENT);
readThis(Tokens.CLOSEBRACKET);
return e;
}
break;
}
case Tokens.LASTVAL : {
if (database.sqlSyntaxPgs) {
read();
readThis(Tokens.OPENBRACKET);
readThis(Tokens.CLOSEBRACKET);
return FunctionCustom.newCustomFunction(session,
Tokens.T_IDENTITY, Tokens.IDENTITY);
}
break;
}
case Tokens.NEXTVAL : {
if (database.sqlSyntaxPgs) {
return readNextvalFunction();
} else if (database.sqlSyntaxDb2) {
e = readSequenceExpressionOrNull(OpTypes.SEQUENCE);
if (e != null) {
return e;
}
}
break;
}
case Tokens.ROW_NUMBER : {
read();
if (token.tokenType == Tokens.OPENBRACKET) {
read();
readThis(Tokens.CLOSEBRACKET);
readThis(Tokens.OVER);
readThis(Tokens.OPENBRACKET);
readThis(Tokens.CLOSEBRACKET);
} else {
rewind(position);
break;
}
return new ExpressionColumn(OpTypes.ROWNUM);
}
case Tokens.ROWNUM : {
read();
if (token.tokenType == Tokens.OPENBRACKET) {
read();
if (token.tokenType == Tokens.CLOSEBRACKET) {
read();
} else {
rewind(position);
break;
}
} else if (!database.sqlSyntaxOra && !database.sqlSyntaxDb2) {
rewind(position);
break;
}
return new ExpressionColumn(OpTypes.ROWNUM);
}
case Tokens.LEFT :
case Tokens.RIGHT :
// CLI function names
break;
case Tokens.TABLE : {
read();
readThis(Tokens.OPENBRACKET);
TableDerived td =
XreadSubqueryTableBody(OpTypes.TABLE_SUBQUERY);
readThis(Tokens.CLOSEBRACKET);
return new Expression(OpTypes.TABLE_SUBQUERY, td);
}
case Tokens.VALUES : {
/*
if (database.sqlSyntaxMys) {
read();
readThis(Tokens.OPENBRACKET);
checkIsSimpleName();
String name = token.tokenString;
if(compileContext.contextuallyTypedExpression) {
e = new ExpressionColumn(name);
} else {
e = new ExpressionValue(null, Type.SQL_INTEGER);
}
read();
readThis(Tokens.CLOSEBRACKET);
return e;
}
*/
throw unexpectedToken();
}
case Tokens.GROUPING : {
read();
readThis(Tokens.OPENBRACKET);
Expression groupingElements = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
return new ExpressionColumn(groupingElements);
}
case Tokens.JSON_ARRAY : {
read();
return readJSONArray();
}
case Tokens.JSON_ARRAYAGG : {
read();
return readJSONArrayAgg();
}
case Tokens.JSON_OBJECT : {
read();
return readJSONObject();
}
case Tokens.JSON_OBJECTAGG : {
read();
return readJSONObjectAgg();
}
default :
if (isCoreReservedKey()) {
throw unexpectedToken();
}
}
e = readColumnOrFunctionExpression();
if (e.isSelfAggregate()) {
readFilterClause(e);
}
return e;
}
Expression readJSONArray() {
HsqlArrayList list = new HsqlArrayList();
Expression qe = null;
boolean nullOnNull = true;
Type dataType = Type.SQL_VARCHAR_LONG;
readThis(Tokens.OPENBRACKET);
int position = getPosition();
loop:
while (true) {
Expression value;
switch (token.tokenType) {
case Tokens.ABSENT :
case Tokens.NULL :
case Tokens.CLOSEBRACKET :
break loop;
case Tokens.COMMA :
if (list.size() == 0) {
throw unexpectedToken();
}
read();
}
try {
value = XreadValueExpression();
list.add(value);
} catch (HsqlException e) {
if (list.size() > 0) {
throw e;
}
rewind(position);
break loop;
}
}
if (list.size() == 0) {
if (token.tokenType != Tokens.CLOSEBRACKET) {
TableDerived td =
XreadSubqueryTableBody(OpTypes.TABLE_SUBQUERY);
qe = new Expression(OpTypes.ARRAY_SUBQUERY, td);
}
}
nullOnNull = readJSONNullClause(nullOnNull);
if (readIfThis(Tokens.RETURNING)) {
dataType = readJSONReturningClause();
}
readThis(Tokens.CLOSEBRACKET);
if (qe == null) {
return new ExpressionJSON.ExpressionJSONArrayFromValues(list,
nullOnNull, dataType);
} else {
return new ExpressionJSON.ExpressionJSONArrayFromQuery(qe,
nullOnNull, dataType);
}
}
Expression readJSONArrayAgg() {
boolean nullOnNull = false;
Type dataType = Type.SQL_VARCHAR_LONG;
Expression valueExpr;
ExpressionArrayAggregate arrayAgg;
SortAndSlice sort = null;
readThis(Tokens.OPENBRACKET);
valueExpr = XreadValueExpression();
if (token.tokenType == Tokens.ORDER) {
read();
readThis(Tokens.BY);
sort = XreadOrderBy();
}
arrayAgg = new ExpressionArrayAggregate(OpTypes.ARRAY_AGG, false,
valueExpr, sort, null);
nullOnNull = readJSONNullClause(nullOnNull);
if (readIfThis(Tokens.RETURNING)) {
dataType = readJSONReturningClause();
}
readThis(Tokens.CLOSEBRACKET);
return new ExpressionJSON.ExpressionJSONArrayAgg(arrayAgg, nullOnNull,
dataType);
}
Expression readJSONObject() {
OrderedHashMap map = new OrderedHashMap();
boolean nullOnNull = true;
boolean uniqueKeys = false;
Type dataType = Type.SQL_VARCHAR_LONG;
boolean hasDuplicate = false;
readThis(Tokens.OPENBRACKET);
loop:
while (true) {
Expression nameExpr;
Expression valueExpr;
boolean isKey = false;
switch (token.tokenType) {
case Tokens.ABSENT :
case Tokens.NULL :
case Tokens.WITH :
case Tokens.WITHOUT :
case Tokens.CLOSEBRACKET :
break loop;
case Tokens.COMMA :
if (map.size() == 0) {
throw unexpectedToken();
}
read();
}
if (readIfThis(Tokens.KEY)) {
isKey = true;
}
int position = getPosition();
nameExpr = XreadCharacterValueExpression();
if (nameExpr.opType == OpTypes.JSON_FUNCTION) {
rewind(position);
throw unexpectedToken();
}
if (!readIfThis(Tokens.VALUE)) {
if (isKey) {
throw unexpectedToken();
}
readThis(Tokens.COLON);
}
valueExpr = XreadValueExpression();
if (readIfThis(Tokens.FORMAT)) {
readThis(Tokens.JSON);
valueExpr =
new ExpressionJSON.ExpressionJSONWrapper(valueExpr);
}
Object e = map.put(nameExpr, valueExpr);
if (e != null) {
hasDuplicate = true;
}
}
nullOnNull = readJSONNullClause(nullOnNull);
uniqueKeys = readJSONUniqueClause(uniqueKeys);
if (uniqueKeys && hasDuplicate) {
throw Error.error(ErrorCode.X_23505);
}
if (readIfThis(Tokens.RETURNING)) {
dataType = readJSONReturningClause();
}
readThis(Tokens.CLOSEBRACKET);
return new ExpressionJSON.ExpressionJSONObject(map, nullOnNull,
uniqueKeys, dataType);
}
Expression readJSONObjectAgg() {
boolean nullOnNull = true;
boolean uniqueKeys = false;
Type dataType = Type.SQL_VARCHAR_LONG;
Expression nameExpr;
Expression valueExpr;
ExpressionArrayAggregate arrayAggName;
ExpressionArrayAggregate arrayAggValue;
readThis(Tokens.OPENBRACKET);
int position = getPosition();
nameExpr = XreadCharacterValueExpression();
if (nameExpr.opType == OpTypes.JSON_FUNCTION) {
rewind(position);
throw unexpectedToken();
}
readThis(Tokens.COLON);
valueExpr = XreadValueExpression();
arrayAggName = new ExpressionArrayAggregate(OpTypes.ARRAY_AGG, false,
nameExpr, null, null);
arrayAggValue = new ExpressionArrayAggregate(OpTypes.ARRAY_AGG, false,
valueExpr, null, null);
nullOnNull = readJSONNullClause(nullOnNull);
uniqueKeys = readJSONUniqueClause(uniqueKeys);
if (readIfThis(Tokens.RETURNING)) {
dataType = readJSONReturningClause();
}
readThis(Tokens.CLOSEBRACKET);
return new ExpressionJSON.ExpressionJSONObjectAgg(arrayAggName,
arrayAggValue, nullOnNull, uniqueKeys, dataType);
}
boolean readJSONNullClause(boolean defaultValue) {
boolean nullOnNull = defaultValue;
switch (token.tokenType) {
case Tokens.ABSENT : {
read();
readThis(Tokens.ON);
readThis(Tokens.NULL);
nullOnNull = false;
break;
}
case Tokens.NULL : {
read();
readThis(Tokens.ON);
readThis(Tokens.NULL);
nullOnNull = true;
break;
}
}
return nullOnNull;
}
boolean readJSONUniqueClause(boolean defaultValue) {
boolean uniqueKeys = defaultValue;
switch (token.tokenType) {
case Tokens.WITH : {
read();
readThis(Tokens.UNIQUE);
readIfThis(Tokens.KEYS);
uniqueKeys = true;
break;
}
case Tokens.WITHOUT : {
read();
readThis(Tokens.UNIQUE);
readIfThis(Tokens.KEYS);
uniqueKeys = false;
break;
}
}
return uniqueKeys;
}
Type readJSONReturningClause() {
int position = getPosition();
Type dataType = readTypeDefinition(false, true);
if (dataType.typeCode == Types.SQL_VARCHAR
|| dataType.typeCode == Types.SQL_CLOB) {
return dataType;
}
rewind(position);
throw super.unexpectedTokenRequire("VARCHAR or CLOB");
}
Expression readNextvalFunction() {
read();
readThis(Tokens.OPENBRACKET);
String spec = readQuotedString();
Scanner scanner = session.getScanner();
scanner.reset(session, spec);
scanner.scanNext();
String schemaName = session.getSchemaName(scanner.token.namePrefix);
NumberSequence sequence =
database.schemaManager.getSequence(scanner.token.tokenString,
schemaName, true);
Expression e = new ExpressionColumn(sequence, OpTypes.SEQUENCE);
readThis(Tokens.CLOSEBRACKET);
return e;
}
// OK - composite production -
//
Expression XreadAllTypesPrimary(boolean boole) {
Expression e = null;
switch (token.tokenType) {
case Tokens.SUBSTRING :
case Tokens.SUBSTRING_REGEX :
case Tokens.LOWER :
case Tokens.UPPER :
case Tokens.TRANSLATE_REGEX :
case Tokens.TRIM :
case Tokens.OVERLAY :
case Tokens.NORMALIZE :
//
case Tokens.POSITION :
case Tokens.OCCURRENCES_REGEX :
case Tokens.POSITION_REGEX :
case Tokens.EXTRACT :
case Tokens.CHAR_LENGTH :
case Tokens.CHARACTER_LENGTH :
case Tokens.OCTET_LENGTH :
case Tokens.CARDINALITY :
case Tokens.ARRAY_MAX_CARDINALITY :
case Tokens.MAX_CARDINALITY :
case Tokens.ABS :
case Tokens.MOD :
case Tokens.LN :
case Tokens.EXP :
case Tokens.POWER :
case Tokens.SQRT :
case Tokens.FLOOR :
case Tokens.CEILING :
case Tokens.CEIL :
case Tokens.WIDTH_BUCKET :
FunctionSQL function =
FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
if (function == null) {
throw unsupportedFeature();
}
e = readSQLFunction(function);
if (e != null) {
break;
}
// fall through
default :
e = XreadAllTypesValueExpressionPrimary(boole);
}
e = XreadModifier(e);
return e;
}
Expression XreadModifier(Expression e) {
int position = getPosition();
switch (token.tokenType) {
case Tokens.AT : {
read();
Expression e1 = null;
if (token.tokenType == Tokens.LOCAL) {
read();
} else if (token.tokenType == Tokens.TIME) {
read();
readThis(Tokens.ZONE);
e1 = XreadValueExpressionPrimary();
switch (token.tokenType) {
case Tokens.YEAR :
case Tokens.MONTH :
case Tokens.DAY :
case Tokens.HOUR :
case Tokens.MINUTE :
case Tokens.SECOND : {
IntervalType type = readIntervalType(session,
false);
if (e1.getType() == OpTypes.SUBTRACT) {
e1.dataType = type;
} else {
e1 = new ExpressionOp(e1, type);
}
break;
}
default :
}
} else {
rewind(position);
return e;
}
e = new ExpressionOp(OpTypes.ZONE_MODIFIER, e, e1);
break;
}
case Tokens.YEAR :
case Tokens.MONTH :
case Tokens.DAY :
case Tokens.HOUR :
case Tokens.MINUTE :
case Tokens.SECOND : {
IntervalType type = readIntervalType(session, true);
if (e.getType() == OpTypes.SUBTRACT) {
e.dataType = type;
} else {
e = new ExpressionOp(e, type);
}
break;
}
case Tokens.COLLATE : {
read();
Collation collation =
database.schemaManager.getCollation(session,
token.tokenString, token.namePrefix);
e.setCollation(collation);
read();
}
}
return e;
}
Expression XreadValueExpressionWithContext() {
Expression e;
compileContext.contextuallyTypedExpression = true;
try {
e = XreadValueExpression();
} finally {
compileContext.contextuallyTypedExpression = false;
}
return e;
}
Expression XreadValueExpressionOnDuplicate() {
Expression e;
compileContext.onDuplicateTypedExpression = true;
try {
e = XreadValueExpression();
} finally {
compileContext.onDuplicateTypedExpression = false;
}
return e;
}
Expression XreadGroupByExpressionPrimary() {
if (token.tokenType == Tokens.GROUPING) {
read();
// simple syntax error if SETS is missing
readThis(Tokens.SETS);
readThis(Tokens.OPENBRACKET);
HsqlArrayList list = new HsqlArrayList();
while (true) {
Expression e = XreadGroupByExpressionPrimary();
list.add(e);
if (token.tokenType == Tokens.COMMA) {
read();
continue;
}
break;
}
readThis(Tokens.CLOSEBRACKET);
Expression[] array = new Expression[list.size()];
list.toArray(array);
Expression e = new Expression(OpTypes.VALUELIST, array);
e.groupingType = Tokens.SETS;
return e;
}
Expression e = XreadGroupByExpression();
return e;
}
Expression XreadGroupByExpression() {
int groupingType = 0;
Expression e;
switch (token.tokenType) {
case Tokens.CUBE :
case Tokens.ROLLUP :
groupingType = token.tokenType;
read();
readThis(Tokens.OPENBRACKET);
e = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
checkIfGroupingOrAggregate(e);
e.groupingType = groupingType;
return e;
case Tokens.OPENBRACKET :
int position = getPosition();
read();
// handle empty set here
if (token.tokenType == Tokens.CLOSEBRACKET) {
read();
return new ExpressionColumn(OpTypes.NONE);
}
rewind(position);
e = XreadValueExpression();
checkIfGroupingOrAggregate(e);
return e;
default :
e = XreadValueExpression();
checkIfGroupingOrAggregate(e);
return e;
}
}
private void checkIfGroupingOrAggregate(Expression e) {
if (e == null) {
return;
}
if (OpTypes.GROUPING == e.opType
|| OpTypes.subqueryAggregateExpressionSet.contains(e.opType)) {
throw Error.error(
ErrorCode.X_42572,
"aggregate functions / subqueries are not allowed in GROUP BY");
}
for (int i = 0; i < e.nodes.length; i++) {
checkIfGroupingOrAggregate(e.nodes[i]);
}
}
/**
* value expression ::=
* common value expression
* | boolean value expression
* | row value expression
*
*/
Expression XreadValueExpression() {
Expression e = XreadAllTypesCommonValueExpression(true);
if (token.tokenType == Tokens.LEFTBRACKET) {
read();
Expression e1 = XreadNumericValueExpression();
readThis(Tokens.RIGHTBRACKET);
e = new ExpressionAccessor(e, e1);
}
return e;
}
// union of
Expression XreadRowOrCommonValueExpression() {
return XreadAllTypesCommonValueExpression(false);
}
// union of
// no and no
Expression XreadAllTypesCommonValueExpression(boolean boole) {
Expression e = XreadAllTypesTerm(boole);
int type = 0;
boolean end = false;
while (true) {
switch (token.tokenType) {
case Tokens.PLUS_OP :
type = OpTypes.ADD;
boole = false;
break;
case Tokens.MINUS_OP :
type = OpTypes.SUBTRACT;
boole = false;
break;
case Tokens.CONCAT_OP :
type = OpTypes.CONCAT;
boole = false;
break;
case Tokens.OR :
if (boole) {
type = OpTypes.OR;
break;
}
// fall through
default :
end = true;
break;
}
if (end) {
break;
}
read();
Expression a = e;
e = XreadAllTypesTerm(boole);
e = boole ? new ExpressionLogical(type, a, e)
: new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadAllTypesTerm(boolean boole) {
Expression e = XreadAllTypesFactor(boole);
int type = 0;
boolean end = false;
while (true) {
switch (token.tokenType) {
case Tokens.ASTERISK :
type = OpTypes.MULTIPLY;
boole = false;
break;
case Tokens.DIVIDE_OP :
type = OpTypes.DIVIDE;
boole = false;
break;
case Tokens.AND :
if (boole) {
type = OpTypes.AND;
break;
}
// fall through
default :
end = true;
break;
}
if (end) {
break;
}
read();
Expression a = e;
e = XreadAllTypesFactor(boole);
if (e == null) {
throw unexpectedToken();
}
e = boole ? new ExpressionLogical(type, a, e)
: new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadAllTypesFactor(boolean boole) {
Expression e;
boolean minus = false;
boolean not = false;
boolean unknown = false;
switch (token.tokenType) {
case Tokens.PLUS_OP :
read();
boole = false;
break;
case Tokens.MINUS_OP :
read();
boole = false;
minus = true;
break;
case Tokens.NOT :
if (boole) {
read();
not = true;
}
break;
default :
}
e = XreadAllTypesPrimary(boole);
if (boole && token.tokenType == Tokens.IS) {
read();
if (token.tokenType == Tokens.NOT) {
read();
not = !not;
}
if (token.tokenType == Tokens.TRUE) {
read();
} else if (token.tokenType == Tokens.FALSE) {
read();
not = !not;
} else if (token.tokenType == Tokens.UNKNOWN) {
read();
unknown = true;
} else {
throw unexpectedToken();
}
}
if (minus) {
e = new ExpressionArithmetic(OpTypes.NEGATE, e);
}
if (unknown) {
e = new ExpressionLogical(OpTypes.IS_NULL, e);
}
if (not) {
e = new ExpressionLogical(OpTypes.NOT, e);
}
return e;
}
Expression XreadStringValueExpression() {
return XreadCharacterValueExpression();
// XreadBinaryValueExpression();
}
Expression XreadCharacterValueExpression() {
Expression e = XreadCharacterPrimary();
Collation collation = readCollateClauseOrNull();
while (token.tokenType == Tokens.CONCAT_OP
|| token.tokenType == Tokens.PLUS_OP) {
read();
Expression a = e;
e = XreadCharacterPrimary();
collation = readCollateClauseOrNull();
e = new ExpressionArithmetic(OpTypes.CONCAT, a, e);
}
return e;
}
Expression XreadCharacterPrimary() {
switch (token.tokenType) {
case Tokens.SUBSTRING :
// case Token.SUBSTRING_REGEX :
case Tokens.LOWER :
case Tokens.UPPER :
// case Token.TRANSLATE_REGEX :
case Tokens.TRIM :
case Tokens.OVERLAY :
// case Token.NORMALIZE :
FunctionSQL function =
FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
Expression e = readSQLFunction(function);
if (e != null) {
return e;
}
}
return XreadValueExpressionPrimary();
}
Expression XreadNumericPrimary() {
switch (token.tokenType) {
case Tokens.POSITION :
// case Token.OCCURRENCES_REGEX :
// case Token.POSITION_REGEX :
case Tokens.EXTRACT :
case Tokens.CHAR_LENGTH :
case Tokens.CHARACTER_LENGTH :
case Tokens.OCTET_LENGTH :
case Tokens.CARDINALITY :
case Tokens.ABS :
case Tokens.MOD :
case Tokens.LN :
case Tokens.EXP :
case Tokens.POWER :
case Tokens.SQRT :
case Tokens.FLOOR :
case Tokens.CEILING :
case Tokens.CEIL :
case Tokens.WIDTH_BUCKET :
FunctionSQL function =
FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
if (function == null) {
throw unexpectedToken();
}
Expression e = readSQLFunction(function);
if (e != null) {
return e;
}
}
return XreadValueExpressionPrimary();
}
Expression XreadNumericValueExpression() {
Expression e = XreadTerm();
while (true) {
int type;
if (token.tokenType == Tokens.PLUS_OP) {
type = OpTypes.ADD;
} else if (token.tokenType == Tokens.MINUS_OP) {
type = OpTypes.SUBTRACT;
} else {
break;
}
read();
Expression a = e;
e = XreadTerm();
e = new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadTerm() {
Expression e = XreadFactor();
int type;
while (true) {
if (token.tokenType == Tokens.ASTERISK) {
type = OpTypes.MULTIPLY;
} else if (token.tokenType == Tokens.DIVIDE_OP) {
type = OpTypes.DIVIDE;
} else {
break;
}
read();
Expression a = e;
e = XreadFactor();
if (e == null) {
throw unexpectedToken();
}
e = new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadFactor() {
Expression e;
boolean minus = false;
if (token.tokenType == Tokens.PLUS_OP) {
read();
} else if (token.tokenType == Tokens.MINUS_OP) {
read();
minus = true;
}
e = XreadNumericPrimary();
if (e == null) {
return null;
}
if (minus) {
e = new ExpressionArithmetic(OpTypes.NEGATE, e);
}
return e;
}
Expression XreadDatetimeValueExpression() {
Expression e = XreadDateTimeIntervalTerm();
while (true) {
int type;
if (token.tokenType == Tokens.PLUS_OP) {
type = OpTypes.ADD;
} else if (token.tokenType == Tokens.MINUS_OP) {
type = OpTypes.SUBTRACT;
} else {
break;
}
read();
Expression a = e;
e = XreadDateTimeIntervalTerm();
e = new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadIntervalValueExpression() {
Expression e = XreadDateTimeIntervalTerm();
while (true) {
int type;
if (token.tokenType == Tokens.PLUS_OP) {
type = OpTypes.ADD;
} else if (token.tokenType == Tokens.MINUS_OP) {
type = OpTypes.SUBTRACT;
} else {
break;
}
read();
Expression a = e;
e = XreadDateTimeIntervalTerm();
e = new ExpressionArithmetic(type, a, e);
}
return e;
}
Expression XreadDateTimeIntervalTerm() {
switch (token.tokenType) {
case Tokens.CURRENT_DATE :
case Tokens.CURRENT_TIME :
case Tokens.CURRENT_TIMESTAMP :
case Tokens.LOCALTIME :
case Tokens.LOCALTIMESTAMP :
//
case Tokens.ABS :
FunctionSQL function =
FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
if (function == null) {
throw unexpectedToken();
}
return readSQLFunction(function);
default :
}
return XreadValueExpressionPrimary();
}
// returns null
Expression XreadDateTimeValueFunctionOrNull() {
FunctionSQL function = null;
switch (token.tokenType) {
case Tokens.CURRENT_DATE :
case Tokens.CURRENT_TIME :
case Tokens.CURRENT_TIMESTAMP :
case Tokens.LOCALTIME :
case Tokens.LOCALTIMESTAMP :
function = FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
break;
case Tokens.SYSTIMESTAMP :
case Tokens.NOW :
case Tokens.TODAY :
case Tokens.SYSDATE :
function = FunctionCustom.newCustomFunction(session,
token.tokenString, token.tokenType);
if (function == null) {
return null;
}
break;
default :
return null;
}
if (function == null) {
throw unexpectedToken();
}
return readSQLFunction(function);
}
Expression XreadBooleanValueExpression() {
try {
Expression e = XreadBooleanTermOrNull();
if (e == null) {
throw Error.error(ErrorCode.X_42568);
}
while (true) {
int type;
if (token.tokenType == Tokens.OR) {
type = OpTypes.OR;
} else {
break;
}
read();
Expression a = e;
e = XreadBooleanTermOrNull();
if (e == null) {
throw Error.error(ErrorCode.X_42568);
}
e = new ExpressionLogical(type, a, e);
}
if (e == null) {
throw Error.error(ErrorCode.X_42568);
}
return e;
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError != null && lastError.getLevel() >= ex.getLevel()) {
ex = lastError;
lastError = null;
}
throw ex;
}
}
Expression XreadBooleanTermOrNull() {
Expression e = XreadBooleanFactorOrNull();
if (e == null) {
return null;
}
int type;
while (true) {
if (token.tokenType == Tokens.AND) {
type = OpTypes.AND;
} else {
break;
}
read();
Expression a = e;
e = XreadBooleanFactorOrNull();
if (e == null) {
throw unexpectedToken();
}
e = new ExpressionLogical(type, a, e);
}
return e;
}
Expression XreadBooleanFactorOrNull() {
Expression e;
boolean not = false;
if (token.tokenType == Tokens.NOT) {
read();
not = true;
}
e = XreadBooleanTestOrNull();
if (e == null) {
return null;
}
if (not) {
e = new ExpressionLogical(OpTypes.NOT, e);
}
return e;
}
Expression XreadBooleanTestOrNull() {
boolean unknown = false;
boolean isNot = false;
Expression e = XreadBooleanPrimaryOrNull();
if (e == null) {
return e;
}
if (token.tokenType == Tokens.IS) {
read();
if (token.tokenType == Tokens.NOT) {
read();
isNot = true;
}
if (token.tokenType == Tokens.TRUE) {
read();
e = new ExpressionLogical(e, new ExpressionBoolean(true));
} else if (token.tokenType == Tokens.FALSE) {
read();
e = new ExpressionLogical(e, new ExpressionBoolean(false));
} else if (token.tokenType == Tokens.UNKNOWN) {
read();
unknown = true;
} else {
throw unexpectedToken();
}
}
if (unknown) {
e = new ExpressionLogical(OpTypes.IS_NULL, e);
}
if (isNot) {
e = new ExpressionLogical(OpTypes.NOT, e);
}
return e;
}
// ::= |
Expression XreadBooleanPrimaryOrNull() {
Expression e = null;
int position;
switch (token.tokenType) {
case Tokens.EXISTS :
case Tokens.UNIQUE :
return XreadPredicate();
case Tokens.ROW :
read();
readThis(Tokens.OPENBRACKET);
e = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
break;
default :
position = getPosition();
try {
e = XreadAllTypesCommonValueExpression(false);
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError == null
|| lastError.getLevel() < ex.getLevel()) {
lastError = ex;
}
rewind(position);
}
}
if (e == null && token.tokenType == Tokens.OPENBRACKET) {
read();
position = getPosition();
try {
e = XreadRowElementList(true);
readThis(Tokens.CLOSEBRACKET);
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError == null
|| lastError.getLevel() < ex.getLevel()) {
lastError = ex;
}
rewind(position);
e = XreadBooleanValueExpression();
readThis(Tokens.CLOSEBRACKET);
}
}
if (e != null) {
e = XreadPredicateRightPart(e);
}
return e;
}
// similar to
Expression XreadBooleanPredicand() {
Expression e;
if (token.tokenType == Tokens.OPENBRACKET) {
read();
e = XreadBooleanValueExpression();
readThis(Tokens.CLOSEBRACKET);
} else {
e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
}
}
return e;
}
Expression XreadPredicate() {
switch (token.tokenType) {
case Tokens.EXISTS : {
read();
Expression s = XreadTableSubquery(OpTypes.EXISTS);
return new ExpressionLogical(OpTypes.EXISTS, s);
}
case Tokens.UNIQUE : {
read();
Expression s = XreadTableSubquery(OpTypes.UNIQUE);
return new ExpressionLogical(OpTypes.UNIQUE, s);
}
default : {
Expression a = XreadRowValuePredicand();
return XreadPredicateRightPart(a);
}
}
}
Expression XreadPredicateRightPart(final Expression l) {
boolean hasNot = false;
boolean immediately = false;
ExpressionLogical e = null;
Expression r;
int position = getPosition();
if (token.tokenType == Tokens.NOT) {
read();
hasNot = true;
}
// valid for PRECEDES and SUCCEEDS predicates
if (token.tokenType == Tokens.IMMEDIATELY) {
read();
if (token.tokenType != Tokens.PRECEDES
&& token.tokenType != Tokens.SUCCEEDS) {
throw unexpectedToken();
}
immediately = true;
}
switch (token.tokenType) {
case Tokens.IS : {
if (hasNot) {
throw unexpectedToken();
}
read();
if (token.tokenType == Tokens.NOT) {
hasNot = true;
read();
}
if (token.tokenType == Tokens.NULL) {
read();
if (hasNot) {
e = new ExpressionLogical(OpTypes.IS_NOT_NULL, l);
hasNot = false;
} else {
e = new ExpressionLogical(OpTypes.IS_NULL, l);
}
break;
}
if (token.tokenType == Tokens.DISTINCT) {
read();
readThis(Tokens.FROM);
r = XreadRowValuePredicand();
e = new ExpressionLogical(OpTypes.NOT_DISTINCT, l, r);
hasNot = !hasNot;
break;
}
rewind(position);
return l;
}
case Tokens.LIKE : {
e = XreadLikePredicateRightPart(l);
break;
}
case Tokens.BETWEEN : {
e = XreadBetweenPredicateRightPart(l);
break;
}
case Tokens.IN : {
e = XreadInPredicateRightPart(l);
break;
}
case Tokens.CONTAINS : {
if (hasNot) {
throw unexpectedToken();
}
e = XreadPeriodPredicateRightPart(OpTypes.RANGE_CONTAINS, l);
break;
}
case Tokens.EQUALS : {
if (hasNot) {
throw unexpectedToken();
}
e = XreadPeriodPredicateRightPart(OpTypes.RANGE_EQUALS, l);
break;
}
case Tokens.OVERLAPS : {
if (hasNot) {
throw unexpectedToken();
}
e = XreadPeriodPredicateRightPart(OpTypes.RANGE_OVERLAPS, l);
break;
}
case Tokens.PRECEDES : {
if (hasNot) {
throw unexpectedToken();
}
if (immediately) {
e = XreadPeriodPredicateRightPart(
OpTypes.RANGE_IMMEDIATELY_PRECEDES, l);
} else {
e = XreadPeriodPredicateRightPart(OpTypes.RANGE_PRECEDES,
l);
}
break;
}
case Tokens.SUCCEEDS : {
if (hasNot) {
throw unexpectedToken();
}
if (immediately) {
e = XreadPeriodPredicateRightPart(
OpTypes.RANGE_IMMEDIATELY_SUCCEEDS, l);
} else {
e = XreadPeriodPredicateRightPart(OpTypes.RANGE_SUCCEEDS,
l);
}
break;
}
case Tokens.EQUALS_OP :
case Tokens.GREATER_EQUALS :
case Tokens.GREATER_OP :
case Tokens.LESS_OP :
case Tokens.LESS_EQUALS :
case Tokens.NOT_EQUALS : {
if (hasNot) {
throw unexpectedToken();
}
int type = getExpressionType(token.tokenType);
read();
switch (token.tokenType) {
case Tokens.ANY :
case Tokens.SOME :
case Tokens.ALL :
e = XreadQuantifiedComparisonRightPart(type, l);
break;
default : {
Expression row = XreadRowValuePredicand();
e = new ExpressionLogical(type, l, row);
break;
}
}
break;
}
case Tokens.MATCH : {
e = XreadMatchPredicateRightPart(l);
break;
}
default : {
if (hasNot) {
throw unexpectedToken();
}
return l;
}
}
if (hasNot) {
e = new ExpressionLogical(OpTypes.NOT, e);
}
return e;
}
private ExpressionLogical XreadBetweenPredicateRightPart(
final Expression a) {
boolean symmetric = false;
read();
if (token.tokenType == Tokens.ASYMMETRIC) {
read();
} else if (token.tokenType == Tokens.SYMMETRIC) {
symmetric = true;
read();
}
Expression left = XreadRowValuePredicand();
readThis(Tokens.AND);
Expression right = XreadRowValuePredicand();
Expression l = new ExpressionLogical(OpTypes.GREATER_EQUAL, a, left);
Expression r = new ExpressionLogical(OpTypes.SMALLER_EQUAL, a, right);
ExpressionLogical leftToRight = new ExpressionLogical(OpTypes.AND, l,
r);
if (symmetric) {
l = new ExpressionLogical(OpTypes.SMALLER_EQUAL, a, left);
r = new ExpressionLogical(OpTypes.GREATER_EQUAL, a, right);
Expression rightToLeft = new ExpressionLogical(OpTypes.AND, l, r);
return new ExpressionLogical(OpTypes.OR, leftToRight, rightToLeft);
} else {
return leftToRight;
}
}
private ExpressionLogical XreadQuantifiedComparisonRightPart(int exprType,
Expression l) {
int tokenType = token.tokenType;
int exprSubType = 0;
Expression e;
switch (token.tokenType) {
case Tokens.ANY :
case Tokens.SOME :
exprSubType = OpTypes.ANY_QUANTIFIED;
break;
case Tokens.ALL :
exprSubType = OpTypes.ALL_QUANTIFIED;
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "ParserDQL");
}
read();
readThis(Tokens.OPENBRACKET);
int position = getPosition();
int brackets = readOpenBrackets();
switch (token.tokenType) {
case Tokens.UNNEST :
e = XreadCollectionDerivedTable(OpTypes.IN);
readThis(Tokens.CLOSEBRACKET);
readCloseBrackets(brackets);
break;
case Tokens.WITH :
case Tokens.TABLE :
case Tokens.VALUES :
case Tokens.SELECT :
rewind(position);
TableDerived td = XreadSubqueryTableBody(OpTypes.IN);
e = new Expression(OpTypes.TABLE_SUBQUERY, td);
readThis(Tokens.CLOSEBRACKET);
break;
default :
rewind(position);
e = readAggregateExpression(tokenType);
readThis(Tokens.CLOSEBRACKET);
readFilterClause(e);
}
ExpressionLogical r = new ExpressionLogical(exprType, l, e);
r.setSubType(exprSubType);
return r;
}
private ExpressionLogical XreadInPredicateRightPart(Expression l) {
int degree = l.getDegree();
Expression e = null;
read();
readThis(Tokens.OPENBRACKET);
int position = getPosition();
int brackets = readOpenBrackets();
switch (token.tokenType) {
case Tokens.UNNEST :
e = XreadCollectionDerivedTable(OpTypes.IN);
readThis(Tokens.CLOSEBRACKET);
readCloseBrackets(brackets);
break;
case Tokens.WITH :
case Tokens.TABLE :
case Tokens.VALUES :
case Tokens.SELECT : {
rewind(position);
TableDerived td = XreadSubqueryTableBody(OpTypes.IN);
e = new Expression(OpTypes.TABLE_SUBQUERY, td);
readThis(Tokens.CLOSEBRACKET);
break;
}
default : {
rewind(position);
e = XreadInValueListConstructor(degree);
readThis(Tokens.CLOSEBRACKET);
break;
}
}
ExpressionLogical r;
r = new ExpressionLogical(OpTypes.EQUAL, l, e);
r.setSubType(OpTypes.ANY_QUANTIFIED);
return r;
}
Expression XreadInValueList(int degree) {
HsqlArrayList list = new HsqlArrayList();
while (true) {
Expression e = XreadValueExpression();
if (e.getType() != OpTypes.ROW) {
e = new Expression(OpTypes.ROW, new Expression[]{ e });
}
list.add(e);
if (token.tokenType == Tokens.COMMA) {
read();
continue;
}
break;
}
Expression[] array = new Expression[list.size()];
list.toArray(array);
Expression e = new Expression(OpTypes.VALUELIST, array);
for (int i = 0; i < array.length; i++) {
if (array[i].getType() != OpTypes.ROW) {
array[i] = new Expression(OpTypes.ROW,
new Expression[]{ array[i] });
}
Expression[] args = array[i].nodes;
if (args.length != degree) {
// SQL error message
throw unexpectedToken();
}
for (int j = 0; j < degree; j++) {
if (args[j].getType() == OpTypes.ROW) {
// SQL error message
throw unexpectedToken();
}
}
}
return e;
}
private ExpressionLogical XreadLikePredicateRightPart(Expression a) {
read();
Expression b = XreadStringValueExpression();
Expression escape = null;
if (token.tokenString.equals(Tokens.T_ESCAPE)) {
read();
escape = XreadStringValueExpression();
}
return new ExpressionLike(a, b, escape);
}
private ExpressionLogical XreadMatchPredicateRightPart(Expression a) {
boolean isUnique = false;
int matchType = OpTypes.MATCH_SIMPLE;
read();
if (token.tokenType == Tokens.UNIQUE) {
read();
isUnique = true;
}
switch (token.tokenType) {
default :
matchType = isUnique ? OpTypes.MATCH_UNIQUE_SIMPLE
: OpTypes.MATCH_SIMPLE;
break;
case Tokens.SIMPLE :
read();
matchType = isUnique ? OpTypes.MATCH_UNIQUE_SIMPLE
: OpTypes.MATCH_SIMPLE;
break;
case Tokens.PARTIAL :
read();
matchType = isUnique ? OpTypes.MATCH_UNIQUE_PARTIAL
: OpTypes.MATCH_PARTIAL;
break;
case Tokens.FULL :
read();
matchType = isUnique ? OpTypes.MATCH_UNIQUE_FULL
: OpTypes.MATCH_FULL;
break;
}
int mode = isUnique ? OpTypes.MATCH_SIMPLE
: OpTypes.IN;
Expression s = XreadTableSubquery(mode);
return new ExpressionLogical(matchType, a, s);
}
/**
* OVERLAPS does not require PERIOD, others do.
* CONTAINS can have single value right side
*/
private ExpressionLogical XreadPeriodPredicateRightPart(int opType,
Expression left) {
boolean isLeftRow = false;
switch (left.getType()) {
case OpTypes.COLUMN :
left = new ExpressionPeriod((ExpressionColumn) left);
break;
case OpTypes.PERIOD :
break;
case OpTypes.ROW :
if (left.nodes.length != 2) {
throw Error.error(ErrorCode.X_42564);
}
isLeftRow = true;
break;
default :
throw Error.error(ErrorCode.X_42564);
}
read();
boolean period = false;
if (token.tokenType == Tokens.PERIOD) {
if (isLeftRow) {
throw unexpectedToken();
}
read();
period = true;
if (token.tokenType != Tokens.OPENBRACKET) {
throw unexpectedTokenRequire(Tokens.T_OPENBRACKET);
}
}
Expression right = XreadRowValuePredicand();
switch (right.getType()) {
case OpTypes.COLUMN :
if (period) {
throw Error.error(ErrorCode.X_42564);
}
right = new ExpressionPeriod((ExpressionColumn) right);
break;
case OpTypes.ROW :
if (right.nodes.length == 2) {
if (period) {
right = new ExpressionPeriod(right);
} else {
if (opType != OpTypes.RANGE_OVERLAPS) {
throw Error.error(ErrorCode.X_42564);
}
return new ExpressionLogical(OpTypes.OVERLAPS, left,
right);
}
break;
}
throw Error.error(ErrorCode.X_42564);
default :
if (opType != OpTypes.RANGE_CONTAINS) {
throw Error.error(ErrorCode.X_42564);
}
if (period) {
throw Error.error(ErrorCode.X_42564);
}
break;
}
return new ExpressionPeriodOp(opType, left, right);
}
Expression XreadRowValueExpression() {
Expression e = XreadExplicitRowValueConstructorOrNull();
if (e != null) {
return e;
}
return XreadRowValueSpecialCase();
}
Expression XreadTableRowValueConstructor() {
Expression e = XreadExplicitRowValueConstructorOrNull();
if (e != null) {
return e;
}
return XreadRowValueSpecialCase();
}
// union of |
// | |
// translated to
// | |
Expression XreadRowValuePredicand() {
return XreadRowOrCommonValueExpression();
}
Expression XreadRowValueSpecialCase() {
Expression e = XreadSimpleValueExpressionPrimary();
if (e != null) {
e = XreadArrayElementReference(e);
}
return e;
}
//
// ISSUE - XreadCommonValueExpression and XreadBooleanValueExpression should merge
Expression XreadRowValueConstructor() {
Expression e;
e = XreadExplicitRowValueConstructorOrNull();
if (e != null) {
return e;
}
e = XreadRowOrCommonValueExpression();
if (e != null) {
return e;
}
return XreadBooleanValueExpression();
}
// returns null
// must be called in conjunction with -1) {
column = rangeVars[i].getColumn(index);
read();
break;
}
}
if (column == null) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
colIndexList.add(index);
if (token.tokenType == Tokens.LEFTBRACKET) {
if (!column.getDataType().isArrayType()) {
throw unexpectedToken();
}
read();
Expression e = XreadNumericValueExpression();
if (e == null) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
e = new ExpressionAccessor(column.getAccessor(), e);
readThis(Tokens.RIGHTBRACKET);
return e;
}
return column.getAccessor();
}
Expression XreadCollectionDerivedTable(int type) {
boolean ordinality = false;
int position = getPosition();
readThis(Tokens.UNNEST);
readThis(Tokens.OPENBRACKET);
compileContext.incrementDepth();
HsqlArrayList list = new HsqlArrayList();
while (true) {
Expression e = XreadValueExpression();
list.add(e);
if (token.tokenType == Tokens.COMMA) {
read();
} else {
break;
}
}
Expression[] array = new Expression[list.size()];
list.toArray(array);
readThis(Tokens.CLOSEBRACKET);
if (token.tokenType == Tokens.WITH) {
read();
readThis(Tokens.ORDINALITY);
ordinality = true;
}
Expression e = new ExpressionTable(array, ordinality);
TableDerived td = newSubQueryTable(e, type);
td.setSQL(getLastPart(position));
compileContext.decrementDepth();
return e;
}
Expression XreadTableFunctionDerivedTable() {
int position = getPosition();
readThis(Tokens.TABLE);
readThis(Tokens.OPENBRACKET);
compileContext.incrementDepth();
Expression e = XreadValueExpression();
if (e.getType() != OpTypes.FUNCTION
&& e.getType() != OpTypes.SQL_FUNCTION) {
compileContext.decrementDepth();
throw unexpectedToken(Tokens.T_TABLE);
}
readThis(Tokens.CLOSEBRACKET);
e = new ExpressionTable(new Expression[]{ e }, false);
TableDerived td = newSubQueryTable(e, OpTypes.TABLE_SUBQUERY);
td.setSQL(getLastPart(position));
compileContext.decrementDepth();
return e;
}
Expression XreadLateralDerivedTable() {
readThis(Tokens.LATERAL);
readThis(Tokens.OPENBRACKET);
TableDerived td = XreadSubqueryTableBody(OpTypes.TABLE_SUBQUERY);
readThis(Tokens.CLOSEBRACKET);
return new Expression(OpTypes.TABLE_SUBQUERY, td);
}
Expression XreadArrayConstructor() {
readThis(Tokens.OPENBRACKET);
TableDerived td = XreadSubqueryTableBody(OpTypes.TABLE_SUBQUERY);
readThis(Tokens.CLOSEBRACKET);
return new Expression(OpTypes.ARRAY_SUBQUERY, td);
}
// Additional Common Elements
Collation readCollateClauseOrNull() {
if (token.tokenType == Tokens.COLLATE) {
read();
Collation collation = database.schemaManager.getCollation(session,
token.tokenString, token.namePrefix);
return collation;
}
return null;
}
Expression XreadArrayElementReference(Expression e) {
if (token.tokenType == Tokens.LEFTBRACKET) {
read();
Expression e1 = XreadNumericValueExpression();
readThis(Tokens.RIGHTBRACKET);
e = new ExpressionAccessor(e, e1);
}
return e;
}
Expression readRow() {
Expression r = null;
while (true) {
Expression e = XreadValueExpressionWithContext();
if (r == null) {
r = e;
} else if (r.getType() == OpTypes.ROW) {
if (e.getType() == OpTypes.ROW
&& r.nodes[0].getType() != OpTypes.ROW) {
r = new Expression(OpTypes.ROW, new Expression[] {
r, e
});
} else {
r.nodes = (Expression[]) ArrayUtil.resizeArray(r.nodes,
r.nodes.length + 1);
r.nodes[r.nodes.length - 1] = e;
}
} else {
r = new Expression(OpTypes.ROW, new Expression[] {
r, e
});
}
if (token.tokenType != Tokens.COMMA) {
break;
}
read();
}
return r;
}
Expression readCaseExpression() {
Expression predicand = null;
read();
if (token.tokenType != Tokens.WHEN) {
predicand = XreadRowValuePredicand();
}
return readCaseWhen(predicand);
}
/**
* Reads part of a CASE .. WHEN expression
*/
private Expression readCaseWhen(final Expression l) {
readThis(Tokens.WHEN);
Expression condition = null;
if (l == null) {
condition = XreadBooleanValueExpression();
} else {
while (true) {
Expression newCondition = XreadPredicateRightPart(l);
if (l == newCondition) {
newCondition =
new ExpressionLogical(l, XreadRowValuePredicand());
}
if (condition == null) {
condition = newCondition;
} else {
condition = new ExpressionLogical(OpTypes.OR, condition,
newCondition);
}
if (token.tokenType == Tokens.COMMA) {
read();
} else {
break;
}
}
}
readThis(Tokens.THEN);
Expression current = XreadValueExpression();
Expression elseExpr = null;
if (token.tokenType == Tokens.WHEN) {
elseExpr = readCaseWhen(l);
} else if (token.tokenType == Tokens.ELSE) {
read();
elseExpr = XreadValueExpression();
readThis(Tokens.END);
readIfThis(Tokens.CASE);
} else {
elseExpr = new ExpressionValue((Object) null, (Type) null);
readThis(Tokens.END);
readIfThis(Tokens.CASE);
}
Expression alt = new ExpressionOp(OpTypes.ALTERNATIVE, current,
elseExpr);
Expression casewhen = new ExpressionOp(OpTypes.CASEWHEN, condition,
alt);
return casewhen;
}
/**
* reads a CASEWHEN expression
*/
private Expression readCaseWhenExpressionOrNull() {
Expression l = null;
int position = getPosition();
if (token.tokenType == Tokens.IF) {
if (database.sqlSyntaxMys || database.sqlSyntaxMss) {}
else {
return null;
}
}
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
l = XreadBooleanValueExpression();
readThis(Tokens.COMMA);
Expression then = XreadValueExpression();
readThis(Tokens.COMMA);
Expression thenelse = new ExpressionOp(OpTypes.ALTERNATIVE, then,
XreadValueExpression());
l = new ExpressionOp(OpTypes.CASEWHEN, l, thenelse);
readThis(Tokens.CLOSEBRACKET);
return l;
}
/**
* Reads a CAST expression
*/
private Expression readCastExpression() {
Expression e;
Type typeObject;
read();
readThis(Tokens.OPENBRACKET);
e = XreadValueExpression();
readThis(Tokens.AS);
typeObject = readTypeDefinition(false, true);
if (e.isUnresolvedParam()) {
e.setDataType(session, typeObject);
} else {
e = new ExpressionOp(e, typeObject);
}
readThis(Tokens.CLOSEBRACKET);
return e;
}
private Expression readConvertExpressionOrNull() {
Expression e;
Expression mode = null;
Type typeObject;
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
if (database.sqlSyntaxMss) {
typeObject = readTypeDefinition(false, true);
readThis(Tokens.COMMA);
e = XreadValueExpression();
if (readIfThis(Tokens.COMMA)) {
mode = this.XreadSimpleValueSpecificationOrNull();
}
} else {
e = XreadValueExpression();
readThis(Tokens.COMMA);
typeObject = Type.getTypeForJDBCConvertToken(token.tokenType);
if (typeObject == null) {
typeObject = readTypeDefinition(false, true);
} else {
read();
}
}
if (e.isUnresolvedParam() && mode == null) {
e.setDataType(session, typeObject);
} else {
e = new ExpressionOp(e, typeObject, mode);
}
readThis(Tokens.CLOSEBRACKET);
return e;
}
/**
* reads a Column or Function expression
*/
private Expression readColumnOrFunctionExpression() {
String name = token.tokenString;
boolean isSimpleQuoted = isDelimitedSimpleName();
Token recordedToken = getRecordedToken();
checkIsIdentifier();
if (isUndelimitedSimpleName()) {
Expression e = readFunction();
if (e != null) {
return e;
}
}
read();
if (token.tokenType != Tokens.OPENBRACKET) {
checkValidCatalogName(recordedToken.namePrePrePrefix);
Expression column =
new ExpressionColumn(recordedToken.namePrePrefix,
recordedToken.namePrefix, name);
return column;
}
RoutineSchema routineSchema =
(RoutineSchema) database.schemaManager.findSchemaObject(session,
name, recordedToken.namePrefix, recordedToken.namePrePrefix,
SchemaObject.FUNCTION);
if (routineSchema == null && recordedToken.namePrefix == null
&& !isViewDefinition) {
String schema = session.getSchemaName(null);
ReferenceObject synonym =
database.schemaManager.findSynonym(recordedToken.tokenString,
schema,
SchemaObject.ROUTINE);
if (synonym != null) {
HsqlName synonymName = synonym.getTarget();
routineSchema =
(RoutineSchema) database.schemaManager.findSchemaObject(
synonymName.name, synonymName.schema.name,
SchemaObject.ROUTINE);
}
}
if (routineSchema == null && isSimpleQuoted) {
HsqlName schema =
database.schemaManager.getDefaultSchemaHsqlName();
routineSchema =
(RoutineSchema) database.schemaManager.findSchemaObject(name,
schema.name, SchemaObject.FUNCTION);
if (routineSchema == null) {
Routine.createRoutines(session, schema, name);
routineSchema =
(RoutineSchema) database.schemaManager.findSchemaObject(
name, schema.name, SchemaObject.FUNCTION);
}
}
if (routineSchema == null) {
if (lastError != null) {
throw lastError;
}
throw Error.error(ErrorCode.X_42501, name);
}
HsqlArrayList list = new HsqlArrayList();
readThis(Tokens.OPENBRACKET);
if (token.tokenType == Tokens.CLOSEBRACKET) {
read();
} else {
while (true) {
Expression e = XreadValueExpression();
list.add(e);
if (token.tokenType == Tokens.COMMA) {
read();
} else {
readThis(Tokens.CLOSEBRACKET);
break;
}
}
}
FunctionSQLInvoked function = new FunctionSQLInvoked(routineSchema);
Expression[] arguments = new Expression[list.size()];
list.toArray(arguments);
function.setArguments(arguments);
compileContext.addFunctionCall(function);
recordedToken.setExpression(routineSchema);
return function;
}
Expression readFunction() {
FunctionSQL function = FunctionCustom.newCustomFunction(session,
token.tokenString, token.tokenType);
if (function != null) {
int pos = getPosition();
try {
Expression e = readSQLFunction(function);
if (e != null) {
return e;
}
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError == null
|| lastError.getLevel() < ex.getLevel()) {
lastError = ex;
}
rewind(pos);
}
} else if (isReservedKey()) {
function = FunctionSQL.newSQLFunction(token.tokenString,
compileContext);
if (function != null) {
Expression e = readSQLFunction(function);
if (e != null) {
return e;
}
}
}
return null;
}
Expression readCollection(int type) {
read();
if (token.tokenType == Tokens.OPENBRACKET) {
return XreadArrayConstructor();
} else {
readThis(Tokens.LEFTBRACKET);
HsqlArrayList list = new HsqlArrayList();
for (int i = 0; ; i++) {
if (token.tokenType == Tokens.RIGHTBRACKET) {
read();
break;
}
if (i > 0) {
readThis(Tokens.COMMA);
}
Expression e = XreadValueExpression();
list.add(e);
}
Expression[] array = new Expression[list.size()];
list.toArray(array);
return new Expression(OpTypes.ARRAY, array);
}
}
private Expression readDecodeExpressionOrNull() {
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression casewhen = null;
Expression alternative = null;
Expression main = XreadValueExpression();
readThis(Tokens.COMMA);
do {
Expression v = XreadValueExpression();
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else {
if (alternative == null) {
throw unexpectedToken();
}
alternative.setRightNode(v);
break;
}
Expression l = new ExpressionLogical(OpTypes.NOT_DISTINCT, main,
v);
Expression r = XreadValueExpression();
Expression a = new ExpressionOp(OpTypes.ALTERNATIVE, r, null);
Expression c = new ExpressionOp(OpTypes.CASEWHEN, l, a);
if (casewhen == null) {
casewhen = c;
} else {
alternative.setRightNode(c);
}
alternative = a;
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else {
alternative.setRightNode(new ExpressionValue(null, null));
break;
}
} while (true);
readThis(Tokens.CLOSEBRACKET);
return casewhen;
}
private Expression readConcatExpressionOrNull() {
Expression root;
Expression r;
// turn into a concatenation
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
root = XreadValueExpression();
readThis(Tokens.COMMA);
do {
r = XreadValueExpression();
root = new ExpressionArithmetic(OpTypes.CONCAT, root, r);
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else if (token.tokenType == Tokens.CLOSEBRACKET) {
readThis(Tokens.CLOSEBRACKET);
break;
}
} while (true);
return root;
}
private Expression readConcatSeparatorExpressionOrNull() {
HsqlArrayList array = new HsqlArrayList();
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression e = XreadValueExpression();
array.add(e);
readThis(Tokens.COMMA);
e = XreadValueExpression();
array.add(e);
readThis(Tokens.COMMA);
do {
e = XreadValueExpression();
array.add(e);
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else if (token.tokenType == Tokens.CLOSEBRACKET) {
readThis(Tokens.CLOSEBRACKET);
break;
}
} while (true);
Expression[] expressions = new Expression[array.size()];
array.toArray(expressions);
return new ExpressionOp(OpTypes.CONCAT_WS, expressions);
}
private Expression readLeastExpressionOrNull() {
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression casewhen = null;
do {
casewhen = readValue(casewhen, OpTypes.SMALLER);
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else {
break;
}
} while (true);
readThis(Tokens.CLOSEBRACKET);
return casewhen;
}
private Expression readGreatestExpressionOrNull() {
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression casewhen = null;
do {
casewhen = readValue(casewhen, OpTypes.GREATER);
if (token.tokenType == Tokens.COMMA) {
readThis(Tokens.COMMA);
} else {
break;
}
} while (true);
readThis(Tokens.CLOSEBRACKET);
return casewhen;
}
private Expression readValue(Expression e, int opType) {
Expression r = XreadValueExpression();
if (e == null) {
return r;
}
Expression l = new ExpressionLogical(opType, e, r);
Expression a = new ExpressionOp(OpTypes.ALTERNATIVE, e, r);
return new ExpressionOp(OpTypes.CASEWHEN, l, a);
}
/**
* Reads a NULLIF expression
*/
private Expression readNullIfExpression() {
read();
readThis(Tokens.OPENBRACKET);
Expression c = XreadValueExpression();
readThis(Tokens.COMMA);
Expression alternative = new ExpressionOp(OpTypes.ALTERNATIVE,
new ExpressionValue((Object) null, (Type) null), c);
c = new ExpressionLogical(c, XreadValueExpression());
c = new ExpressionOp(OpTypes.CASEWHEN, c, alternative);
readThis(Tokens.CLOSEBRACKET);
return c;
}
/**
* Reads a ISNULL or ISNULL of NVL expression
*/
private Expression readIfNullExpressionOrNull() {
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression c = XreadValueExpression();
readThis(Tokens.COMMA);
Expression e = XreadValueExpression();
Expression condition = new ExpressionLogical(OpTypes.IS_NULL, c);
Expression alt = new ExpressionOp(OpTypes.ALTERNATIVE, e, c);
c = new ExpressionOp(OpTypes.CASEWHEN, condition, alt);
c.setSubType(OpTypes.CAST);
alt.setSubType(OpTypes.CAST);
readThis(Tokens.CLOSEBRACKET);
return c;
}
/**
* Reads a NVL2 expression
*/
private Expression readIfNull2ExpressionOrNull() {
int position = getPosition();
read();
if (!readIfThis(Tokens.OPENBRACKET)) {
rewind(position);
return null;
}
Expression c = XreadValueExpression();
readThis(Tokens.COMMA);
Expression e1 = XreadValueExpression();
readThis(Tokens.COMMA);
Expression e2 = XreadValueExpression();
Expression condition = new ExpressionLogical(OpTypes.IS_NULL, c);
Expression alt = new ExpressionOp(OpTypes.ALTERNATIVE, e2, e1);
c = new ExpressionOp(OpTypes.CASEWHEN, condition, alt);
c.setSubType(OpTypes.CAST);
alt.setSubType(OpTypes.CAST);
readThis(Tokens.CLOSEBRACKET);
return c;
}
/**
* Reads a COALESE expression
*/
private Expression readCoalesceExpression() {
Expression c = null;
read();
readThis(Tokens.OPENBRACKET);
Expression leaf = null;
while (true) {
Expression current = XreadValueExpression();
if (leaf != null && token.tokenType == Tokens.CLOSEBRACKET) {
readThis(Tokens.CLOSEBRACKET);
leaf.setLeftNode(current);
break;
}
Expression expressionNull = new ExpressionValue((Object) null,
(Type) null);
Expression condition = new ExpressionLogical(OpTypes.IS_NULL,
current);
Expression alt = new ExpressionOp(OpTypes.ALTERNATIVE,
expressionNull, current);
Expression casewhen = new ExpressionOp(OpTypes.CASEWHEN,
condition, alt);
if (session.database.sqlSyntaxMys) {
alt.setSubType(OpTypes.CAST);
casewhen.setSubType(OpTypes.CAST);
}
if (c == null) {
c = casewhen;
} else {
leaf.setLeftNode(casewhen);
}
leaf = alt;
readThis(Tokens.COMMA);
}
return c;
}
Expression readSQLFunction(FunctionSQL function) {
int position = getPosition();
read();
short[] parseList = function.parseList;
if (parseList.length == 0) {
return function;
}
HsqlArrayList exprList = new HsqlArrayList();
boolean isOpenBracket = token.tokenType == Tokens.OPENBRACKET;
if (!isOpenBracket) {
if (parseList[0] == Tokens.X_OPTION) {
return function;
} else {
rewind(position);
return null;
}
}
try {
readExpression(exprList, parseList, 0, parseList.length, false);
lastError = null;
} catch (HsqlException e) {
if (function.parseListAlt == null) {
throw e;
}
rewind(position);
read();
parseList = function.parseListAlt;
exprList = new HsqlArrayList();
readExpression(exprList, parseList, 0, parseList.length, false);
lastError = null;
}
Expression[] expr = new Expression[exprList.size()];
exprList.toArray(expr);
function.setArguments(expr);
return function.getFunctionExpression();
}
void readExpression(HsqlArrayList exprList, short[] parseList, int start,
int count, boolean isOption) {
for (int i = start; i < start + count; i++) {
int exprType = parseList[i];
switch (exprType) {
case Tokens.QUESTION : {
Expression e = null;
e = XreadAllTypesCommonValueExpression(false);
exprList.add(e);
continue;
}
case Tokens.X_TOKEN : {
if (super.isUndelimitedSimpleName()) {
Expression e = new ExpressionValue(token.tokenString,
Type.SQL_VARCHAR);
read();
exprList.add(e);
continue;
}
throw unexpectedToken();
}
case Tokens.X_POS_INTEGER : {
Expression e = null;
Integer value = readIntegerObject();
if (value.intValue() < 0) {
throw Error.error(ErrorCode.X_42592);
}
e = new ExpressionValue(value, Type.SQL_INTEGER);
exprList.add(e);
continue;
}
case Tokens.X_OPTION : {
i++;
int expressionCount = exprList.size();
int position = getPosition();
int elementCount = parseList[i++];
int initialExprIndex = exprList.size();
try {
readExpression(exprList, parseList, i, elementCount,
true);
} catch (HsqlException ex) {
ex.setLevel(compileContext.subqueryDepth);
if (lastError == null
|| lastError.getLevel() < ex.getLevel()) {
lastError = ex;
}
rewind(position);
exprList.setSize(expressionCount);
for (int j = i; j < i + elementCount; j++) {
if (parseList[j] == Tokens.QUESTION
|| parseList[j] == Tokens.X_KEYSET
|| parseList[j] == Tokens.X_POS_INTEGER) {
exprList.add(null);
}
}
i += elementCount - 1;
continue;
}
if (initialExprIndex == exprList.size()) {
if (parseList[i] != Tokens.OPENBRACKET) {
exprList.add(null);
}
}
i += elementCount - 1;
continue;
}
case Tokens.X_REPEAT : {
i++;
int elementCount = parseList[i++];
int parseIndex = i;
while (true) {
int initialExprIndex = exprList.size();
readExpression(exprList, parseList, parseIndex,
elementCount, true);
if (exprList.size() == initialExprIndex) {
break;
}
}
i += elementCount - 1;
continue;
}
case Tokens.X_KEYSET : {
int elementCount = parseList[++i];
Expression e = null;
if (ArrayUtil.find(parseList, token.tokenType, i
+ 1, elementCount) == -1) {
if (!isOption) {
throw unexpectedToken();
}
} else {
e = new ExpressionValue(
ValuePool.getInt(token.tokenType),
Type.SQL_INTEGER);
read();
}
exprList.add(e);
i += elementCount;
continue;
}
case Tokens.OPENBRACKET :
case Tokens.CLOSEBRACKET :
case Tokens.COMMA :
default :
if (token.tokenType != exprType) {
throw unexpectedToken();
}
read();
}
}
}
private Expression readSequenceExpressionOrNull(int opType) {
int position = getPosition();
switch (opType) {
case OpTypes.SEQUENCE :
if (token.tokenType == Tokens.NEXT) {
read();
if (token.tokenType != Tokens.VALUE) {
rewind(position);
return null;
}
readThis(Tokens.VALUE);
} else if (database.sqlSyntaxDb2
&& token.tokenType == Tokens.NEXTVAL) {
read();
} else if (database.sqlSyntaxDb2
&& token.tokenType == Tokens.PREVVAL) {
read();
} else {
rewind(position);
return null;
}
break;
case OpTypes.SEQUENCE_CURRENT :
read();
readThis(Tokens.VALUE);
break;
default :
}
readThis(Tokens.FOR);
checkIsSchemaObjectName();
NumberSequence sequence = database.schemaManager.findSequence(session,
token.tokenString, token.namePrefix);
if (sequence == null) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
Token recordedToken = getRecordedToken();
read();
Expression e = new ExpressionColumn(sequence, opType);
recordedToken.setExpression(sequence);
compileContext.addSequence(sequence);
return e;
}
SimpleName readSimpleName() {
checkIsSimpleName();
SimpleName name = HsqlNameManager.getSimpleName(token.tokenString,
isDelimitedIdentifier());
read();
return name;
}
HsqlName readNewSchemaName() {
HsqlName name = readNewSchemaObjectName(SchemaObject.SCHEMA, false);
SqlInvariants.checkSchemaNameNotSystem(name.name);
return name;
}
HsqlName readNewSchemaObjectName(int type, boolean checkSchema) {
checkIsSchemaObjectName();
HsqlName hsqlName = database.nameManager.newHsqlName(token.tokenString,
isDelimitedIdentifier(), type);
if (token.namePrefix != null) {
switch (type) {
case SchemaObject.LABEL :
case SchemaObject.VARIABLE :
case SchemaObject.GRANTEE :
case SchemaObject.CATALOG :
throw unexpectedToken();
case SchemaObject.CURSOR : {
if (token.namePrePrefix == null
&& !token.isDelimitedPrefix
&& (Tokens.T_MODULE.equals(token.namePrefix))) {
// local
} else {
throw unexpectedTokenRequire(Tokens.T_MODULE);
}
break;
}
case SchemaObject.SCHEMA : {
checkValidCatalogName(token.namePrefix);
if (token.namePrePrefix != null) {
throw tooManyIdentifiers();
}
break;
}
case SchemaObject.SERVER :
case SchemaObject.WRAPPER : {
checkValidCatalogName(token.namePrefix);
if (token.namePrePrefix != null) {
throw tooManyIdentifiers();
}
break;
}
case SchemaObject.COLUMN : {
throw tooManyIdentifiers();
}
default : {
checkValidCatalogName(token.namePrePrefix);
HsqlName schemaName;
if (checkSchema) {
schemaName =
session.getSchemaHsqlName(token.namePrefix);
} else {
schemaName =
session.database.schemaManager.findSchemaHsqlName(
token.namePrefix);
if (schemaName == null) {
schemaName = database.nameManager.newHsqlName(
token.namePrefix, isDelimitedIdentifier(),
SchemaObject.SCHEMA);
}
}
hsqlName.setSchemaIfNull(schemaName);
break;
}
}
}
read();
return hsqlName;
}
HsqlName readNewDependentSchemaObjectName(HsqlName parentName, int type) {
HsqlName name = readNewSchemaObjectName(type, true);
name.parent = parentName;
name.setSchemaIfNull(parentName.schema);
if (name.schema != null && parentName.schema != null
&& name.schema != parentName.schema) {
throw Error.error(ErrorCode.X_42505, token.namePrefix);
}
return name;
}
HsqlName readSchemaName() {
checkIsSchemaObjectName();
checkValidCatalogName(token.namePrefix);
HsqlName schema = session.getSchemaHsqlName(token.tokenString);
read();
return schema;
}
SchemaObject readSchemaObjectName(int type) {
checkIsSchemaObjectName();
checkValidCatalogName(token.namePrePrefix);
String schema = session.getSchemaName(token.namePrefix);
SchemaObject object =
database.schemaManager.getSchemaObject(token.tokenString, schema,
type);
read();
return object;
}
SchemaObject readSchemaObjectName(HsqlName schemaName, int type) {
checkIsSchemaObjectName();
SchemaObject object =
database.schemaManager.getSchemaObject(token.tokenString,
schemaName.name, type);
if (token.namePrefix != null) {
if (!token.namePrefix.equals(schemaName.name)) {
// todo - better error message
throw Error.error(ErrorCode.X_42505, token.namePrefix);
}
if (token.namePrePrefix != null) {
if (!token.namePrePrefix.equals(
database.getCatalogName().name)) {
// todo - better error message
throw Error.error(ErrorCode.X_42505, token.namePrefix);
}
}
}
read();
return object;
}
Table readTableName() {
return readTableName(false);
}
Table readTableName(boolean orSynonym) {
checkIsIdentifier();
lastSynonym = null;
Table table = database.schemaManager.findTable(session,
token.tokenString, token.namePrefix, token.namePrePrefix);
if (table == null) {
boolean trySynonym = orSynonym && token.namePrefix == null
&& !isViewDefinition;
if (trySynonym) {
ReferenceObject reference = database.schemaManager.findSynonym(
token.tokenString,
session.getCurrentSchemaHsqlName().name,
SchemaObject.TABLE);
if (reference != null) {
table = (Table) database.schemaManager.getSchemaObject(
reference.getTarget());
lastSynonym = reference.getName();
}
}
if (table == null) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
}
getRecordedToken().setExpression(table);
read();
return table;
}
/**
* Returns a period condition (including a default) for all tables with a
* system period. Otherwise null;
*/
ExpressionPeriodOp XreadQuerySystemPeriodSpecOrNull(Table table) {
int position = getPosition();
if (!table.isSystemVersioned()) {
return null;
}
if (token.tokenType == Tokens.FOR) {
read();
} else {
ExpressionPeriodOp periodExpression = new ExpressionPeriodOp();
return periodExpression;
}
if (token.tokenType == Tokens.SYSTEM_TIME) {
read();
} else {
rewind(position);
return null;
}
switch (token.tokenType) {
case Tokens.AS : {
read();
readThis(Tokens.OF);
Expression point = XreadValueExpression();
return new ExpressionPeriodOp(point);
}
case Tokens.BETWEEN : {
read();
readIfThis(Tokens.ASYMMETRIC);
Expression pointStart = XreadRowValuePredicand();
readThis(Tokens.AND);
Expression pointEnd = XreadRowValuePredicand();
return new ExpressionPeriodOp(pointStart, pointEnd);
}
case Tokens.FROM : {
read();
Expression pointStart = XreadValueExpression();
readThis(Tokens.TO);
Expression pointEnd = XreadValueExpression();
return new ExpressionPeriodOp(pointStart, pointEnd);
}
default :
throw unexpectedToken();
}
}
ExpressionPeriodOp XreadQueryApplicationPeriodSpecOrNull(Table table) {
PeriodDefinition period = table.getApplicationPeriod();
if (period == null) {
return null;
}
if (token.tokenType == Tokens.FOR) {
read();
} else {
return null;
}
readThis(Tokens.PORTION);
readThis(Tokens.OF);
checkIsSimpleName();
if (!token.tokenString.equals(period.periodName.getNameString())) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
read();
readThis(Tokens.FROM);
Expression pointStart = XreadValueExpression();
readThis(Tokens.TO);
Expression pointEnd = XreadValueExpression();
ExpressionPeriod left = new ExpressionPeriod(period);
ExpressionPeriod right = new ExpressionPeriod(pointStart, pointEnd);
return new ExpressionPeriodOp(OpTypes.RANGE_OVERLAPS, left, right);
}
ColumnSchema readSimpleColumnName(RangeVariable rangeVar,
boolean withPrefix) {
ColumnSchema column = null;
checkIsIdentifier();
if (!withPrefix && token.namePrefix != null) {
throw tooManyIdentifiers();
}
int index = rangeVar.findColumn(token.namePrePrefix, token.namePrefix,
token.tokenString);
if (index == -1) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
column = rangeVar.getTable().getColumn(index);
read();
return column;
}
ColumnSchema readSimpleColumnName(Table table, boolean withPrefix) {
checkIsIdentifier();
if (withPrefix) {
if (token.namePrefix != null
&& !table.getName().name.equals(token.namePrefix)) {
throw Error.error(ErrorCode.X_42501, token.namePrefix);
}
} else if (token.namePrefix != null) {
throw tooManyIdentifiers();
}
int index = table.findColumn(token.tokenString);
if (index == -1) {
throw Error.error(ErrorCode.X_42501, token.tokenString);
}
ColumnSchema column = table.getColumn(index);
read();
return column;
}
StatementQuery compileDeclareCursorOrNull(RangeGroup[] rangeGroups,
boolean isRoutine) {
int sensitivity = ResultConstants.SQL_ASENSITIVE;
int scrollability = ResultConstants.SQL_NONSCROLLABLE;
int holdability = ResultConstants.SQL_NONHOLDABLE;
int returnability = ResultConstants.SQL_WITHOUT_RETURN;
int position = getPosition();
readThis(Tokens.DECLARE);
if (isReservedKey()) {
rewind(position);
return null;
}
HsqlName cursorName = readNewSchemaObjectName(SchemaObject.CURSOR,
false);
switch (token.tokenType) {
case Tokens.SENSITIVE :
read();
sensitivity = ResultConstants.SQL_SENSITIVE;
break;
case Tokens.INSENSITIVE :
read();
sensitivity = ResultConstants.SQL_INSENSITIVE;
break;
case Tokens.ASENSITIVE :
read();
break;
default :
}
if (token.tokenType == Tokens.NO) {
readThis(Tokens.SCROLL);
} else {
if (token.tokenType == Tokens.SCROLL) {
read();
scrollability = ResultConstants.SQL_SCROLLABLE;
}
}
if (token.tokenType != Tokens.CURSOR) {
rewind(position);
return null;
}
readThis(Tokens.CURSOR);
for (int round = 0; round < 2; round++) {
if (token.tokenType == Tokens.WITH) {
read();
if (round == 0 && token.tokenType == Tokens.HOLD) {
read();
holdability = ResultConstants.SQL_HOLDABLE;
} else {
readThis(Tokens.RETURN);
round++;
returnability = ResultConstants.SQL_WITH_RETURN;
}
} else if (token.tokenType == Tokens.WITHOUT) {
read();
if (round == 0 && token.tokenType == Tokens.HOLD) {
read();
} else {
readThis(Tokens.RETURN);
round++;
}
}
}
readThis(Tokens.FOR);
int props = ResultProperties.getProperties(sensitivity,
ResultConstants.SQL_UPDATABLE, scrollability, holdability,
returnability);
StatementQuery cs = compileCursorSpecification(rangeGroups, props,
isRoutine);
cs.setCursorName(cursorName);
return cs;
}
/**
* Retrieves a SELECT or other query expression Statement from this parse context.
*/
StatementQuery compileCursorSpecification(RangeGroup[] rangeGroups,
int props, boolean isRoutine) {
OrderedHashSet colNames = null;
QueryExpression queryExpression = XreadQueryExpression();
if (token.tokenType == Tokens.FOR) {
read();
if (token.tokenType == Tokens.READ
|| token.tokenType == Tokens.FETCH) {
read();
readThis(Tokens.ONLY);
props = ResultProperties.addUpdatable(props, false);
} else {
readThis(Tokens.UPDATE);
props = ResultProperties.addUpdatable(props, true);
if (token.tokenType == Tokens.OF) {
readThis(Tokens.OF);
colNames = new OrderedHashSet();
readColumnNameList(colNames, null, false);
}
if (database.sqlSyntaxOra) {
readIfThis(Tokens.NOWAIT);
}
}
}
if (database.sqlSyntaxDb2) {
if (readIfThis(Tokens.WITH)) {
if (!readIfThis("CS")) {
if (!readIfThis("RR")) {
if (!readIfThis("RS")) {
readThis("UR");
}
}
}
}
if (readIfThis(Tokens.USE)) {
readThis(Tokens.AND);
readThis(Tokens.T_KEEP);
if (!readIfThis(Tokens.T_EXCLUSIVE)) {
if (!readIfThis(Tokens.T_SHARE)) {
readThis(Tokens.UPDATE);
}
}
readThis(Tokens.LOCKS);
}
}
if (ResultProperties.isUpdatable(props)) {
queryExpression.isUpdatable = true;
}
queryExpression.setReturningResult();
if (database.sqlLowerCaseIdentifier && !isRoutine) {
queryExpression.setLowerCaseResultIdentifer();
}
queryExpression.resolve(session, rangeGroups, null);
StatementQuery cs = isRoutine
? new StatementCursor(session, queryExpression,
compileContext)
: new StatementQuery(session, queryExpression,
compileContext);
return cs;
}
StatementDMQL compileShortCursorSpecification(int props) {
QueryExpression select = XreadSimpleTable();
if (ResultProperties.isUpdatable(props)) {
select.isUpdatable = true;
}
select.setReturningResult();
select.resolve(session);
StatementDMQL cs = new StatementQuery(session, select, compileContext);
return cs;
}
int readCloseBrackets(int limit) {
int count = 0;
while (count < limit && token.tokenType == Tokens.CLOSEBRACKET) {
read();
count++;
}
return count;
}
int readOpenBrackets() {
int count = 0;
while (token.tokenType == Tokens.OPENBRACKET) {
count++;
read();
}
return count;
}
void readNestedParenthesisedTokens() {
readThis(Tokens.OPENBRACKET);
do {
read();
if (token.tokenType == Tokens.OPENBRACKET) {
readNestedParenthesisedTokens();
}
if (token.tokenType == Tokens.X_ENDPARSE) {
throw unexpectedToken();
}
} while (token.tokenType != Tokens.CLOSEBRACKET);
read();
}
void checkValidCatalogName(String name) {
if (name != null && !name.equals(database.getCatalogName().name)) {
throw Error.error(ErrorCode.X_42501, name);
}
}
void rewind(int position) {
super.rewind(position);
compileContext.rewind(position);
}
public static final class CompileContext {
final Session session;
final ParserBase parser;
final CompileContext baseContext;
final int basePosition;
boolean isViewTable;
//
private int subqueryDepth;
private HsqlArrayList namedSubqueries;
//
private OrderedIntKeyHashMap parameters = new OrderedIntKeyHashMap();
private HsqlArrayList usedSequences = new HsqlArrayList(16, true);
private HsqlArrayList usedRoutines = new HsqlArrayList(16, true);
private OrderedIntKeyHashMap rangeVariables =
new OrderedIntKeyHashMap();
private HsqlArrayList usedObjects = new HsqlArrayList(16, true);
Type currentDomain;
boolean contextuallyTypedExpression;
boolean onDuplicateTypedExpression;
Routine callProcedure;
//
private RangeGroup[] outerRangeGroups = RangeGroup.emptyArray;
//
private final int initialRangeVarIndex;
private int rangeVarIndex;
public CompileContext(Session session) {
this(session, null, null);
}
public CompileContext(Session session, ParserBase parser,
CompileContext baseContext) {
this.session = session;
this.parser = parser;
this.baseContext = baseContext;
if (baseContext == null) {
initialRangeVarIndex = rangeVarIndex = 1;
basePosition = 0;
} else {
initialRangeVarIndex = rangeVarIndex =
baseContext.getRangeVarCount();
basePosition = baseContext.parser.getPosition();
subqueryDepth = baseContext.getDepth();
}
}
public void reset() {
rangeVarIndex = initialRangeVarIndex;
subqueryDepth = 0;
rangeVariables.clear();
parameters.clear();
usedSequences.clear();
usedRoutines.clear();
callProcedure = null;
usedObjects.clear();
outerRangeGroups = RangeGroup.emptyArray;
//
currentDomain = null;
contextuallyTypedExpression = false;
}
public int getDepth() {
return subqueryDepth;
}
public void incrementDepth() {
subqueryDepth++;
if (baseContext != null) {
baseContext.subqueryDepth++;
}
}
public void decrementDepth() {
clearSubqueries();
subqueryDepth--;
if (baseContext != null) {
baseContext.subqueryDepth--;
}
}
public void decrementDepth(int toDepth) {
while (subqueryDepth > toDepth) {
decrementDepth();
}
}
public void rewind(int position) {
if (baseContext != null) {
baseContext.rewind(basePosition + position);
return;
}
rewindRangeVariables(position);
rewindParameters(position);
}
private void rewindRangeVariables(int position) {
for (int i = rangeVariables.size() - 1; i >= 0; i--) {
int rangePos = rangeVariables.getKeyAt(i, -1);
if (rangePos > position) {
rangeVariables.removeEntry(i);
}
}
if (rangeVariables.size() > 0) {
RangeVariable range =
(RangeVariable) rangeVariables.getValueAt(
rangeVariables.size() - 1);
rangeVarIndex = range.rangePosition + 1;
} else {
rangeVarIndex = initialRangeVarIndex;
}
}
private void rewindParameters(int position) {
if (baseContext != null) {
baseContext.rewindParameters(basePosition + position);
return;
}
Iterator it = parameters.keySet().iterator();
while (it.hasNext()) {
int pos = it.nextInt();
if (pos >= position) {
it.remove();
}
}
}
public void setCurrentSubquery(HsqlName name) {
isViewTable = name.type == SchemaObject.VIEW;
}
public void registerRangeVariable(RangeVariable range) {
int nextRangePosition = basePosition;
if (parser != null) {
nextRangePosition += parser.getPosition();
}
if (isViewTable) {
range.isViewSubquery = true;
}
registerRangeVariable(range, nextRangePosition);
}
private void registerRangeVariable(RangeVariable range, int position) {
if (baseContext != null) {
baseContext.registerRangeVariable(range, position);
return;
}
range.rangePosition = getNextRangeVarIndex();
range.level = subqueryDepth;
rangeVariables.put(position, range);
}
public void setNextRangeVarIndex(int n) {
if (baseContext != null) {
baseContext.setNextRangeVarIndex(n);
return;
}
rangeVarIndex = n;
}
private int getNextRangeVarIndex() {
if (baseContext != null) {
return baseContext.getNextRangeVarIndex();
}
return rangeVarIndex++;
}
public int getNextResultRangeVarIndex() {
RangeVariable range = new RangeVariable(null, null, false,
RangeVariable.PLACEHOLDER_RANGE);
registerRangeVariable(range);
return range.rangePosition;
}
public int getRangeVarCount() {
if (baseContext != null) {
return baseContext.getRangeVarCount();
}
return rangeVarIndex;
}
public RangeVariable[] getAllRangeVariables() {
HsqlArrayList list = new HsqlArrayList();
for (int i = 0; i < rangeVariables.size(); i++) {
RangeVariable range =
(RangeVariable) rangeVariables.getValueAt(i);
if (range.rangeType != RangeVariable.PLACEHOLDER_RANGE) {
list.add(range);
}
}
RangeVariable[] array = new RangeVariable[list.size()];
list.toArray(array);
return array;
}
public RangeGroup[] getOuterRanges() {
if (baseContext != null) {
return baseContext.outerRangeGroups;
}
return outerRangeGroups;
}
public void setOuterRanges(RangeGroup[] rangeGroups) {
outerRangeGroups = rangeGroups;
}
public NumberSequence[] getSequences() {
if (usedSequences.size() == 0) {
return NumberSequence.emptyArray;
}
NumberSequence[] array = new NumberSequence[usedSequences.size()];
usedSequences.toArray(array);
return array;
}
public Routine[] getRoutines() {
if (callProcedure == null && usedRoutines.size() == 0) {
return Routine.emptyArray;
}
OrderedHashSet set = new OrderedHashSet();
for (int i = 0; i < usedRoutines.size(); i++) {
FunctionSQLInvoked function =
(FunctionSQLInvoked) usedRoutines.get(i);
if (function.routine != null) {
set.add(function.routine);
}
}
if (callProcedure != null) {
set.add(callProcedure);
}
Routine[] array = new Routine[set.size()];
set.toArray(array);
return array;
}
private void initSubqueryNames() {
if (namedSubqueries == null) {
namedSubqueries = new HsqlArrayList();
}
if (namedSubqueries.size() <= subqueryDepth) {
namedSubqueries.setSize(subqueryDepth + 1);
}
OrderedHashMap set =
(OrderedHashMap) namedSubqueries.get(subqueryDepth);
if (set == null) {
set = new OrderedHashMap();
namedSubqueries.set(subqueryDepth, set);
}
}
private void clearSubqueries() {
if (namedSubqueries != null) {
if (namedSubqueries.size() > subqueryDepth) {
OrderedHashMap set =
(OrderedHashMap) namedSubqueries.get(subqueryDepth);
if (set != null) {
set.clear();
}
}
}
}
private void registerSubquery(String name) {
initSubqueryNames();
OrderedHashMap set =
(OrderedHashMap) namedSubqueries.get(subqueryDepth);
boolean added = set.add(name, null);
if (!added) {
throw Error.error(ErrorCode.X_42504, name);
}
}
private void registerSubquery(String name, TableDerived td) {
OrderedHashMap set =
(OrderedHashMap) namedSubqueries.get(subqueryDepth);
set.put(name, td);
}
private void unregisterSubqueries() {
if (namedSubqueries == null) {
return;
}
for (int i = subqueryDepth; i < namedSubqueries.size(); i++) {
namedSubqueries.set(i, null);
}
}
private TableDerived getNamedSubQuery(String name) {
if (baseContext != null) {
TableDerived td = baseContext.getNamedSubQuery(name);
if (td != null) {
return td;
}
}
if (namedSubqueries == null) {
return null;
}
for (int i = subqueryDepth; i >= 0; i--) {
if (namedSubqueries.size() <= i) {
continue;
}
OrderedHashMap set = (OrderedHashMap) namedSubqueries.get(i);
if (set == null) {
continue;
}
TableDerived td = (TableDerived) set.get(name);
if (td != null) {
return td;
}
}
return null;
}
private void addParameter(ExpressionColumn e, int position) {
parameters.put(position, e);
}
private void addSchemaObject(SchemaObject object) {
usedObjects.add(object);
}
private void addSequence(SchemaObject object) {
usedSequences.add(object);
}
void addFunctionCall(FunctionSQLInvoked function) {
usedRoutines.add(function);
}
void addProcedureCall(Routine procedure) {
callProcedure = procedure;
}
ExpressionColumn[] getParameters() {
if (parameters.size() == 0) {
return ExpressionColumn.emptyArray;
}
ExpressionColumn[] result =
new ExpressionColumn[parameters.size()];
parameters.valuesToArray(result);
parameters.clear();
return result;
}
public OrderedHashSet getSchemaObjectNames() {
OrderedHashSet set = new OrderedHashSet();
for (int i = 0; i < usedSequences.size(); i++) {
SchemaObject object = (SchemaObject) usedSequences.get(i);
set.add(object.getName());
}
for (int i = 0; i < usedObjects.size(); i++) {
SchemaObject object = (SchemaObject) usedObjects.get(i);
set.add(object.getName());
}
for (int i = 0; i < rangeVariables.size(); i++) {
RangeVariable range =
(RangeVariable) rangeVariables.getValueAt(i);
if (range.isViewSubquery) {
continue;
}
if (range.rangeType == RangeVariable.PLACEHOLDER_RANGE) {
continue;
}
HsqlName name = range.rangeTable.getName();
if (name.type == SchemaObject.TRANSITION) {
set.addAll(range.getColumnNames());
continue;
}
if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
continue;
}
set.add(name);
set.addAll(range.getColumnNames());
if (range.periodCondition != null) {
if (range.periodCondition.isSystemVersionCondition()) {
set.add(range.rangeTable.systemPeriod.getName());
}
}
}
Routine[] routines = getRoutines();
for (int i = 0; i < routines.length; i++) {
set.add(routines[i].getSpecificName());
}
return set;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy