This commit is contained in:
lukaseder 2017-03-29 16:44:55 +02:00
commit 114a7574c4
3 changed files with 278 additions and 65 deletions

View File

@ -18134,7 +18134,7 @@ public class DSL {
String[] columns = new String[size];
for (int i = 0; i < size; i++)
columns[i] = "c" + i;
columns[i] = "c" + (i + 1);
return new Values<Record>(rows).as("v", columns);
}

View File

@ -104,10 +104,12 @@ import static org.jooq.impl.DSL.ltrim;
import static org.jooq.impl.DSL.max;
import static org.jooq.impl.DSL.maxDistinct;
import static org.jooq.impl.DSL.md5;
import static org.jooq.impl.DSL.median;
import static org.jooq.impl.DSL.mid;
import static org.jooq.impl.DSL.min;
import static org.jooq.impl.DSL.minDistinct;
import static org.jooq.impl.DSL.minute;
import static org.jooq.impl.DSL.mode;
import static org.jooq.impl.DSL.month;
import static org.jooq.impl.DSL.nthValue;
import static org.jooq.impl.DSL.ntile;
@ -150,6 +152,7 @@ import static org.jooq.impl.DSL.reverse;
import static org.jooq.impl.DSL.right;
import static org.jooq.impl.DSL.rollup;
import static org.jooq.impl.DSL.round;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.rowNumber;
import static org.jooq.impl.DSL.rownum;
import static org.jooq.impl.DSL.rowsBetweenCurrentRow;
@ -184,15 +187,18 @@ import static org.jooq.impl.DSL.time;
import static org.jooq.impl.DSL.timestamp;
import static org.jooq.impl.DSL.trim;
import static org.jooq.impl.DSL.unique;
import static org.jooq.impl.DSL.values;
import static org.jooq.impl.DSL.varPop;
import static org.jooq.impl.DSL.varSamp;
import static org.jooq.impl.DSL.when;
import static org.jooq.impl.DSL.year;
import static org.jooq.impl.ParserImpl.Type.A;
import static org.jooq.impl.ParserImpl.Type.B;
import static org.jooq.impl.ParserImpl.Type.D;
import static org.jooq.impl.ParserImpl.Type.N;
import static org.jooq.impl.ParserImpl.Type.S;
import static org.jooq.impl.Tools.EMPTY_COLLECTION;
import static org.jooq.impl.Tools.EMPTY_COMMON_TABLE_EXPRESSION;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.EMPTY_NAME;
@ -216,12 +222,14 @@ import org.jooq.AlterIndexFinalStep;
import org.jooq.AlterIndexStep;
import org.jooq.AlterSchemaFinalStep;
import org.jooq.AlterSchemaStep;
import org.jooq.AlterSequenceStep;
import org.jooq.AlterTableDropStep;
import org.jooq.AlterTableFinalStep;
import org.jooq.AlterTableStep;
import org.jooq.CaseConditionStep;
import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep;
import org.jooq.CommonTableExpression;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@ -241,11 +249,11 @@ import org.jooq.DatePart;
import org.jooq.Delete;
import org.jooq.DeleteFinalStep;
import org.jooq.DeleteWhereStep;
import org.jooq.DerivedColumnList;
import org.jooq.DropIndexFinalStep;
import org.jooq.DropIndexOnStep;
import org.jooq.DropSchemaFinalStep;
import org.jooq.DropSchemaStep;
import org.jooq.DropSequenceFinalStep;
import org.jooq.DropTableFinalStep;
import org.jooq.DropTableStep;
import org.jooq.DropViewFinalStep;
@ -261,12 +269,14 @@ import org.jooq.MergeMatchedStep;
import org.jooq.MergeNotMatchedStep;
import org.jooq.Name;
import org.jooq.OrderedAggregateFunction;
import org.jooq.OrderedAggregateFunctionOfDeferredType;
import org.jooq.Param;
import org.jooq.Parser;
import org.jooq.Queries;
import org.jooq.Query;
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.RowN;
import org.jooq.Schema;
import org.jooq.Select;
import org.jooq.Sequence;
@ -450,6 +460,13 @@ class ParserImpl implements Parser {
break;
case 'w':
case 'W':
if (peekKeyword(ctx, "WITH"))
return parseWith(ctx);
break;
case '(':
// TODO are there other possible statement types?
return parseSelect(ctx);
@ -470,8 +487,42 @@ class ParserImpl implements Parser {
// Statement parsing
// -----------------------------------------------------------------------------------------------------------------
private static final Query parseWith(ParserContext ctx) {
parseKeyword(ctx, "WITH");
List<CommonTableExpression<?>> cte = new ArrayList<CommonTableExpression<?>>();
do {
Name table = parseIdentifier(ctx);
// [#6022] Allow unquoted identifiers for columns
parse(ctx, '(');
List<Name> columnNames = parseIdentifiers(ctx);
String[] columns = new String[columnNames.size()];
for (int i = 0; i < columns.length; i++)
columns[i] = columnNames.get(i).last();
parse(ctx, ')');
DerivedColumnList dcl = table.fields(columns);
parseKeyword(ctx, "AS");
parse(ctx, '(');
cte.add(dcl.as(parseSelect(ctx)));
parse(ctx, ')');
}
while (parseIf(ctx, ','));
// TODO Better model API for WITH clause
return parseSelect(ctx, (WithImpl) new WithImpl(ctx.dsl.configuration(), false).with(cte.toArray(EMPTY_COMMON_TABLE_EXPRESSION)));
// TODO Other statements than SELECT
}
private static final SelectQueryImpl<Record> parseSelect(ParserContext ctx) {
SelectQueryImpl<Record> result = parseQueryPrimary(ctx);
return parseSelect(ctx, null);
}
private static final SelectQueryImpl<Record> parseSelect(ParserContext ctx, WithImpl with) {
SelectQueryImpl<Record> result = parseQueryPrimary(ctx, with);
CombineOperator combine;
while ((combine = parseCombineOperatorIf(ctx)) != null) {
switch (combine) {
@ -518,6 +569,10 @@ class ParserImpl implements Parser {
if (parseKeywordIf(ctx, "ROWS") || parseKeywordIf(ctx, "ROW"))
offsetStandard = true;
// Ingres doesn't have a ROWS keyword after offset
else if (peekKeyword(ctx, "FETCH"))
offsetStandard = true;
else
offsetPostgres = true;
}
@ -570,8 +625,12 @@ class ParserImpl implements Parser {
}
private static final SelectQueryImpl<Record> parseQueryPrimary(ParserContext ctx) {
return parseQueryPrimary(ctx, null);
}
private static final SelectQueryImpl<Record> parseQueryPrimary(ParserContext ctx, WithImpl with) {
if (parseIf(ctx, '(')) {
SelectQueryImpl<Record> result = parseSelect(ctx);
SelectQueryImpl<Record> result = parseSelect(ctx, with);
parse(ctx, ')');
return result;
}
@ -584,6 +643,7 @@ class ParserImpl implements Parser {
if (!distinct)
parseKeywordIf(ctx, "ALL");
// T-SQL style TOP .. START AT
if (parseKeywordIf(ctx, "TOP")) {
limit = parseUnsignedInteger(ctx);
@ -591,6 +651,17 @@ class ParserImpl implements Parser {
offset = parseUnsignedInteger(ctx);
}
// Informix style SKIP .. FIRST
else if (parseKeywordIf(ctx, "SKIP")) {
offset = parseUnsignedInteger(ctx);
if (parseKeywordIf(ctx, "FIRST"))
limit = parseUnsignedInteger(ctx);
}
else if (parseKeywordIf(ctx, "FIRST")) {
limit = parseUnsignedInteger(ctx);
}
List<Field<?>> select = parseSelectList(ctx);
List<Table<?>> from = null;
Condition startWith = null;
@ -670,7 +741,7 @@ class ParserImpl implements Parser {
// TODO support WINDOW
SelectQueryImpl<Record> result = (SelectQueryImpl<Record>) ctx.dsl.selectQuery();
SelectQueryImpl<Record> result = new SelectQueryImpl<Record>(ctx.dsl.configuration(), with);
if (distinct)
result.setDistinct(distinct);
@ -881,10 +952,14 @@ class ParserImpl implements Parser {
if (parseKeywordIf(ctx, "TABLE"))
return parseCreateTable(ctx);
if (parseKeywordIf(ctx, "INDEX"))
return parseCreateIndex(ctx);
else if (parseKeywordIf(ctx, "INDEX"))
return parseCreateIndex(ctx, false);
else if (parseKeywordIf(ctx, "UNIQUE INDEX"))
return parseCreateIndex(ctx, true);
else if (parseKeywordIf(ctx, "SCHEMA"))
return parseCreateSchema(ctx);
else if (parseKeywordIf(ctx, "SEQUENCE"))
return parseCreateSequence(ctx);
else if (parseKeywordIf(ctx, "VIEW"))
return parseCreateView(ctx);
else
@ -900,6 +975,8 @@ class ParserImpl implements Parser {
return parseAlterIndex(ctx);
else if (parseKeywordIf(ctx, "SCHEMA"))
return parseAlterSchema(ctx);
else if (parseKeywordIf(ctx, "SEQUENCE"))
return parseAlterSequence(ctx);
else if (parseKeywordIf(ctx, "VIEW"))
return parseAlterView(ctx);
else
@ -1000,17 +1077,41 @@ class ParserImpl implements Parser {
return s1;
}
private static final DDLQuery parseCreateSequence(ParserContext ctx) {
boolean ifNotExists = parseKeywordIf(ctx, "IF NOT EXISTS");
Sequence<?> schemaName = parseSequenceName(ctx);
return ifNotExists
? ctx.dsl.createSequenceIfNotExists(schemaName)
: ctx.dsl.createSequence(schemaName);
}
private static final DDLQuery parseAlterSequence(ParserContext ctx) {
boolean ifExists = parseKeywordIf(ctx, "IF EXISTS");
Sequence<?> sequenceName = parseSequenceName(ctx);
AlterSequenceStep s1 = ifExists
? ctx.dsl.alterSequenceIfExists(sequenceName)
: ctx.dsl.alterSequence(sequenceName);
if (parseKeywordIf(ctx, "RENAME TO"))
return s1.renameTo(parseSequenceName(ctx));
else if (parseKeywordIf(ctx, "RESTART"))
if (parseKeywordIf(ctx, "WITH"))
return s1.restartWith(parseUnsignedInteger(ctx));
else
return s1.restart();
else
throw ctx.unexpectedToken();
}
private static final DDLQuery parseDropSequence(ParserContext ctx) {
boolean ifExists = parseKeywordIf(ctx, "IF EXISTS");
Sequence<?> sequenceName = parseSequenceName(ctx);
DropSequenceFinalStep s1;
s1 = ifExists
return ifExists
? ctx.dsl.dropSequenceIfExists(sequenceName)
: ctx.dsl.dropSequence(sequenceName);
return s1;
}
private static final DDLQuery parseCreateTable(ParserContext ctx) {
@ -1492,7 +1593,7 @@ class ParserImpl implements Parser {
return s2;
}
private static final DDLQuery parseCreateIndex(ParserContext ctx) {
private static final DDLQuery parseCreateIndex(ParserContext ctx, boolean unique) {
boolean ifNotExists = parseKeywordIf(ctx, "IF NOT EXISTS");
Name indexName = parseIndexName(ctx);
parseKeyword(ctx, "ON");
@ -1506,8 +1607,12 @@ class ParserImpl implements Parser {
CreateIndexStep s1 = ifNotExists
? ctx.dsl.createIndexIfNotExists(indexName)
: ctx.dsl.createIndex(indexName);
? unique
? ctx.dsl.createUniqueIndexIfNotExists(indexName)
: ctx.dsl.createIndexIfNotExists(indexName)
: unique
? ctx.dsl.createUniqueIndex(indexName)
: ctx.dsl.createIndex(indexName);
CreateIndexWhereStep s2 = s1.on(tableName, fieldNames);
CreateIndexFinalStep s3 = condition != null
? s2.where(condition)
@ -1768,6 +1873,10 @@ class ParserImpl implements Parser {
result = table(parseSelect(ctx));
parse(ctx, ')');
}
else if (peekKeyword(ctx, "VALUES")) {
result = parseTableValueConstructor(ctx);
parse(ctx, ')');
}
else {
int parens = 0;
@ -1810,6 +1919,24 @@ class ParserImpl implements Parser {
return result;
}
private static final Table<?> parseTableValueConstructor(ParserContext ctx) {
parseKeyword(ctx, "VALUES");
List<RowN> rows = new ArrayList<RowN>();
do {
rows.add(parseRow(ctx));
}
while (parseIf(ctx, ','));
return values(rows.toArray(Tools.EMPTY_ROWN));
}
private static final RowN parseRow(ParserContext ctx) {
parse(ctx, '(');
RowN row = row(parseFields(ctx));
parse(ctx, ')');
return row;
}
private static final Table<?> parseJoinedTable(ParserContext ctx) {
Table<?> result = parseTableFactor(ctx);
@ -1839,8 +1966,7 @@ class ParserImpl implements Parser {
case JOIN:
case LEFT_OUTER_JOIN:
case FULL_OUTER_JOIN:
case RIGHT_OUTER_JOIN:
case OUTER_APPLY: {
case RIGHT_OUTER_JOIN: {
boolean on = parseKeywordIf(ctx, "ON");
if (on) {
@ -1887,25 +2013,29 @@ class ParserImpl implements Parser {
List<SortField<?>> result = new ArrayList<SortField<?>>();
do {
Field<?> field = parseField(ctx);
SortField<?> sort;
if (parseKeywordIf(ctx, "DESC"))
sort = field.desc();
else if (parseKeywordIf(ctx, "ASC") || true)
sort = field.asc();
if (parseKeywordIf(ctx, "NULLS FIRST"))
sort = sort.nullsFirst();
else if (parseKeywordIf(ctx, "NULLS LAST"))
sort = sort.nullsLast();
result.add(sort);
result.add(parseSortField(ctx));
}
while (parseIf(ctx, ','));
return result;
}
private static final SortField<?> parseSortField(ParserContext ctx) {
Field<?> field = parseField(ctx);
SortField<?> sort;
if (parseKeywordIf(ctx, "DESC"))
sort = field.desc();
else if (parseKeywordIf(ctx, "ASC") || true)
sort = field.asc();
if (parseKeywordIf(ctx, "NULLS FIRST"))
sort = sort.nullsFirst();
else if (parseKeywordIf(ctx, "NULLS LAST"))
sort = sort.nullsLast();
return sort;
}
private static final List<Field<?>> parseFields(ParserContext ctx) {
parseWhitespaceIf(ctx);
@ -1922,10 +2052,17 @@ class ParserImpl implements Parser {
}
static enum Type {
D,
S,
N,
B;
A("array"),
D("date"),
S("string"),
N("numeric"),
B("boolean");
private final String name;
private Type(String name) {
this.name = name;
}
boolean is(Type type) {
return type == null || type == this;
@ -2037,6 +2174,10 @@ class ParserImpl implements Parser {
else if ((field = parseFieldAtan2If(ctx)) != null)
return field;
if (A.is(type))
if ((field = parseArrayValueConstructorIf(ctx)) != null)
return field;
break;
case 'b':
@ -2408,6 +2549,25 @@ class ParserImpl implements Parser {
return parseFieldName(ctx);
}
private static final Field<?> parseArrayValueConstructorIf(ParserContext ctx) {
if (parseKeywordIf(ctx, "ARRAY")) {
parse(ctx, '[');
List<? extends Field<? extends Object[]>> fields;
if (parseIf(ctx, ']')) {
fields = Collections.emptyList();
}
else {
fields = (List) parseFields(ctx);
parse(ctx, ']');
}
return DSL.array(fields);
}
return null;
}
private static final Field<?> parseFieldAtan2If(ParserContext ctx) {
if (parseKeywordIf(ctx, "ATN2") || parseKeywordIf(ctx, "ATAN2")) {
parse(ctx, '(');
@ -3433,7 +3593,7 @@ class ParserImpl implements Parser {
// Hypothetical set function
List<Field<?>> args = parseFields(ctx);
parse(ctx, ')');
AggregateFilterStep<?> result = parseWithinGroup(ctx, rank(args));
AggregateFilterStep<?> result = parseWithinGroupN(ctx, rank(args));
return result;
}
@ -3450,7 +3610,7 @@ class ParserImpl implements Parser {
// Hypothetical set function
List<Field<?>> args = parseFields(ctx);
parse(ctx, ')');
AggregateFilterStep<?> result = parseWithinGroup(ctx, denseRank(args));
AggregateFilterStep<?> result = parseWithinGroupN(ctx, denseRank(args));
return result;
}
@ -3467,7 +3627,7 @@ class ParserImpl implements Parser {
// Hypothetical set function
List<Field<?>> args = parseFields(ctx);
parse(ctx, ')');
AggregateFilterStep<?> result = parseWithinGroup(ctx, percentRank(args));
AggregateFilterStep<?> result = parseWithinGroupN(ctx, percentRank(args));
return result;
}
@ -3484,7 +3644,7 @@ class ParserImpl implements Parser {
// Hypothetical set function
List<Field<?>> args = parseFields(ctx);
parse(ctx, ')');
AggregateFilterStep<?> result = parseWithinGroup(ctx, cumeDist(args));
AggregateFilterStep<?> result = parseWithinGroupN(ctx, cumeDist(args));
return result;
}
@ -3647,18 +3807,23 @@ class ParserImpl implements Parser {
private static final WindowBeforeOverStep<?> parseOrderedSetFunctionIf(ParserContext ctx) {
// TODO Listagg set function
OrderedAggregateFunction<?> ordered;
OrderedAggregateFunction<?> orderedN;
OrderedAggregateFunctionOfDeferredType ordered1;
ordered = parseHypotheticalSetFunctionif(ctx);
if (ordered == null)
ordered = parseInverseDistributionFunctionif(ctx);
if (ordered == null)
return null;
orderedN = parseHypotheticalSetFunctionIf(ctx);
if (orderedN == null)
orderedN = parseInverseDistributionFunctionIf(ctx);
if (orderedN != null)
return parseWithinGroupN(ctx, orderedN);
return parseWithinGroup(ctx, ordered);
ordered1 = parseModeIf(ctx);
if (ordered1 != null)
return parseWithinGroup1(ctx, ordered1);
return null;
}
private static final AggregateFilterStep<?> parseWithinGroup(ParserContext ctx, OrderedAggregateFunction<?> ordered) {
private static final AggregateFilterStep<?> parseWithinGroupN(ParserContext ctx, OrderedAggregateFunction<?> ordered) {
parseKeyword(ctx, "WITHIN GROUP");
parse(ctx, '(');
parseKeyword(ctx, "ORDER BY");
@ -3667,7 +3832,16 @@ class ParserImpl implements Parser {
return result;
}
private static final OrderedAggregateFunction<?> parseHypotheticalSetFunctionif(ParserContext ctx) {
private static final AggregateFilterStep<?> parseWithinGroup1(ParserContext ctx, OrderedAggregateFunctionOfDeferredType ordered) {
parseKeyword(ctx, "WITHIN GROUP");
parse(ctx, '(');
parseKeyword(ctx, "ORDER BY");
AggregateFilterStep<?> result = ordered.withinGroupOrderBy(parseSortField(ctx));
parse(ctx, ')');
return result;
}
private static final OrderedAggregateFunction<?> parseHypotheticalSetFunctionIf(ParserContext ctx) {
// This currently never parses hypothetical set functions, as the function names are already
// consumed earlier in parseFieldTerm(). We should implement backtracking...
@ -3699,7 +3873,7 @@ class ParserImpl implements Parser {
return ordered;
}
private static final OrderedAggregateFunction<BigDecimal> parseInverseDistributionFunctionif(ParserContext ctx) {
private static final OrderedAggregateFunction<BigDecimal> parseInverseDistributionFunctionIf(ParserContext ctx) {
OrderedAggregateFunction<BigDecimal> ordered;
if (parseKeywordIf(ctx, "PERCENTILE_CONT")) {
@ -3718,6 +3892,20 @@ class ParserImpl implements Parser {
return ordered;
}
private static final OrderedAggregateFunctionOfDeferredType parseModeIf(ParserContext ctx) {
OrderedAggregateFunctionOfDeferredType ordered;
if (parseKeywordIf(ctx, "MODE")) {
parse(ctx, '(');
parse(ctx, ')');
ordered = mode();
}
else
ordered = null;
return ordered;
}
private static final AggregateFunction<?> parseGeneralSetFunctionIf(ParserContext ctx) {
boolean distinct;
Field arg;
@ -3727,7 +3915,19 @@ class ParserImpl implements Parser {
return null;
parse(ctx, '(');
distinct = parseSetQuantifier(ctx);
switch (operation) {
case AVG:
case MAX:
case MIN:
case SUM:
distinct = parseSetQuantifier(ctx);
break;
default:
distinct = false;
break;
}
arg = parseField(ctx);
parse(ctx, ')');
@ -3740,6 +3940,8 @@ class ParserImpl implements Parser {
return distinct ? minDistinct(arg) : min(arg);
case SUM:
return distinct ? sumDistinct(arg) : sum(arg);
case MEDIAN:
return median(arg);
case EVERY:
return every(arg);
case ANY:
@ -4272,6 +4474,8 @@ class ParserImpl implements Parser {
return ComputationalOperation.MIN;
else if (parseKeywordIf(ctx, "SUM"))
return ComputationalOperation.SUM;
else if (parseKeywordIf(ctx, "MEDIAN"))
return ComputationalOperation.MEDIAN;
else if (parseKeywordIf(ctx, "EVERY") || parseKeywordIf(ctx, "BOOL_AND"))
return ComputationalOperation.EVERY;
else if (parseKeywordIf(ctx, "ANY") || parseKeywordIf(ctx, "SOME") || parseKeywordIf(ctx, "BOOL_OR"))
@ -4310,6 +4514,10 @@ class ParserImpl implements Parser {
return Comparator.GREATER_OR_EQUAL;
else if (parseIf(ctx, ">"))
return Comparator.GREATER;
// MySQL DISTINCT operator
else if (parseIf(ctx, "<=>"))
return Comparator.IS_NOT_DISTINCT_FROM;
else if (parseIf(ctx, "<="))
return Comparator.LESS_OR_EQUAL;
else if (parseIf(ctx, "<"))
@ -4629,6 +4837,7 @@ class ParserImpl implements Parser {
STDDEV_SAMP,
VAR_SAMP,
VAR_POP,
MEDIAN,
// COLLECT,
// FUSION,
// INTERSECTION;

View File

@ -123,6 +123,7 @@ import org.jooq.AttachableInternal;
import org.jooq.BindContext;
import org.jooq.Catalog;
import org.jooq.Clause;
import org.jooq.CommonTableExpression;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Context;
@ -144,6 +145,7 @@ import org.jooq.RenderContext.CastMode;
import org.jooq.Result;
import org.jooq.Results;
import org.jooq.Row;
import org.jooq.RowN;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.Select;
@ -177,26 +179,28 @@ import org.jooq.types.UShort;
*/
final class Tools {
static final JooqLogger log = JooqLogger.getLogger(Tools.class);
static final JooqLogger log = JooqLogger.getLogger(Tools.class);
// ------------------------------------------------------------------------
// Empty arrays for use with Collection.toArray()
// ------------------------------------------------------------------------
static final Class<?>[] EMPTY_CLASS = {};
static final Clause[] EMPTY_CLAUSE = {};
static final Collection<?>[] EMPTY_COLLECTION = {};
static final ExecuteListener[] EMPTY_EXECUTE_LISTENER = {};
static final Field<?>[] EMPTY_FIELD = {};
static final int[] EMPTY_INT = {};
static final Param<?>[] EMPTY_PARAM = {};
static final Query[] EMPTY_QUERY = {};
static final QueryPart[] EMPTY_QUERYPART = {};
static final Record[] EMPTY_RECORD = {};
static final String[] EMPTY_STRING = {};
static final Name[] EMPTY_NAME = {};
static final TableRecord<?>[] EMPTY_TABLE_RECORD = {};
static final UpdatableRecord<?>[] EMPTY_UPDATABLE_RECORD = {};
static final Class<?>[] EMPTY_CLASS = {};
static final Clause[] EMPTY_CLAUSE = {};
static final Collection<?>[] EMPTY_COLLECTION = {};
static final ExecuteListener[] EMPTY_EXECUTE_LISTENER = {};
static final Field<?>[] EMPTY_FIELD = {};
static final int[] EMPTY_INT = {};
static final Param<?>[] EMPTY_PARAM = {};
static final Query[] EMPTY_QUERY = {};
static final QueryPart[] EMPTY_QUERYPART = {};
static final Record[] EMPTY_RECORD = {};
static final RowN[] EMPTY_ROWN = {};
static final CommonTableExpression<?>[] EMPTY_COMMON_TABLE_EXPRESSION = {};
static final String[] EMPTY_STRING = {};
static final Name[] EMPTY_NAME = {};
static final TableRecord<?>[] EMPTY_TABLE_RECORD = {};
static final UpdatableRecord<?>[] EMPTY_UPDATABLE_RECORD = {};
// ------------------------------------------------------------------------
// Some constants for use with Context.data()