Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jaxdb.jsql.Command Maven / Gradle / Ivy
/* Copyright (c) 2021 JAX-DB
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* You should have received a copy of The MIT License (MIT) along with this
* program. If not, see .
*/
package org.jaxdb.jsql;
import static org.libj.lang.Assertions.*;
import java.io.Closeable;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import org.jaxdb.jsql.Callbacks.OnCommit;
import org.jaxdb.jsql.Callbacks.OnExecute;
import org.jaxdb.jsql.Callbacks.OnNotify;
import org.jaxdb.jsql.Callbacks.OnRollback;
import org.jaxdb.jsql.keyword.Case;
import org.jaxdb.jsql.keyword.Delete.DELETE;
import org.jaxdb.jsql.keyword.Delete._DELETE;
import org.jaxdb.jsql.keyword.Insert.INSERT;
import org.jaxdb.jsql.keyword.Insert._INSERT;
import org.jaxdb.jsql.keyword.Keyword;
import org.jaxdb.jsql.keyword.Update.SET;
import org.jaxdb.jsql.keyword.Update.UPDATE;
import org.jaxdb.vendor.DbVendor;
import org.libj.lang.Throwables;
import org.libj.lang.UUIDs;
import org.libj.sql.AuditConnection;
import org.libj.sql.AuditStatement;
import org.libj.sql.ResultSets;
import org.libj.sql.exception.SQLExceptions;
import org.libj.util.ArrayUtil;
import org.libj.util.function.ToBooleanFunction;
abstract class Command extends Keyword implements Closeable {
@SuppressWarnings("unchecked")
public final E onExecute(final OnExecute onExecute) {
getCallbacks().addOnExecute(onExecute);
return (E)this;
}
private boolean closed;
Callbacks callbacks;
Callbacks getCallbacks() {
return callbacks == null ? callbacks = new Callbacks() : callbacks;
}
void assertNotClosed() {
if (closed)
throw new IllegalStateException("statement is closed");
}
@Override
public void close() {
closed = true;
}
abstract static class Modification extends Command {
data.Table entity;
private Modification(final data.Table entity) {
this.entity = entity;
}
final void revertEntity() {
if (entity != null)
entity.revert();
}
@Override
public final void close() {
super.close();
if (entity != null)
entity._commitEntity$();
}
String sessionId;
@SuppressWarnings("unchecked")
public final C onCommit(final OnCommit onCommit) {
getCallbacks().addOnCommit(onCommit);
return (C)this;
}
@SuppressWarnings("unchecked")
public final R onRollback(final OnRollback onRollback) {
getCallbacks().addOnRollback(onRollback);
return (R)this;
}
}
private static final data.Column>[] emptyColumns = {};
private static data.Column>[] recurseColumns(final data.Column>[] columns, final ToBooleanFunction> predicate, final int length, final int index, final int depth) {
if (index == length)
return depth == 0 ? emptyColumns : new data.Column>[depth];
final data.Column> column = columns[index];
final boolean include = predicate.applyAsBoolean(column);
if (!include)
return recurseColumns(columns, predicate, length, index + 1, depth);
final data.Column>[] results = recurseColumns(columns, predicate, length, index + 1, depth + 1);
results[depth] = column;
return results;
}
static final class Insert extends Command.Modification implements _INSERT, keyword.Insert.CONFLICT_ACTION_NOTIFY, keyword.Insert.ON_CONFLICT {
private data.Column>[] columns;
private data.Column>[] primaries;
final data.Column>[] autos;
private keyword.Select.untyped.SELECT> select;
private boolean isOnConflict;
private data.Column>[] onConflictColumns;
private boolean doUpdate;
Insert(final data.Table entity) {
super(entity);
this.columns = null;
this.autos = recurseColumns(entity._auto$, c -> c.setByCur != data.Column.SetBy.USER, entity._auto$.length, 0, 0);
}
Insert(final data.Column> column, final data.Column>[] columns) {
super(null);
this.columns = ArrayUtil.splice(columns, 0, 0, column);
final data.Table table = this.columns[0].getTable();
for (int i = 1, i$ = this.columns.length; i < i$; ++i) // [A]
if (!this.columns[i].getTable().equals(table))
throw new IllegalArgumentException("All columns must belong to the same Table");
this.primaries = recurseColumns(this.columns, c -> c.primaryIndexType != null, this.columns.length, 0, 0);
this.autos = recurseColumns(this.columns, c -> c.setByCur != data.Column.SetBy.USER && c.generateOnInsert == GenerateOn.AUTO_GENERATED, this.columns.length, 0, 0);
}
@Override
public keyword.Insert.CONFLICT_ACTION_NOTIFY onNotify(final OnNotify onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
@Override
public keyword.Insert.CONFLICT_ACTION_NOTIFY onNotify(final boolean onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
@Override
public INSERT VALUES(final keyword.Select.untyped.SELECT> select) {
this.select = select;
return this;
}
@Override
public keyword.Insert.ON_CONFLICT ON_CONFLICT() {
isOnConflict = true;
if (entity != null)
onConflictColumns = entity._primary$;
else if (primaries != null)
onConflictColumns = primaries;
return this;
}
@Override
public keyword.Insert.CONFLICT_ACTION DO_UPDATE() {
doUpdate = true;
return this;
}
@Override
public keyword.Insert.CONFLICT_ACTION DO_NOTHING() {
doUpdate = false;
return this;
}
@Override
final data.Table getTable() {
if (entity != null)
return entity;
if (columns != null)
return entity = columns[0].getTable();
throw new UnsupportedOperationException("Expected insert.entities != null || insert.select != null");
}
@Override
final data.Column> getColumn() {
throw new UnsupportedOperationException();
}
@Override
void compile(final Compilation compilation, final boolean isExpression) throws IOException, SQLException {
final data.Column>[] columns = this.columns != null ? this.columns : entity._column$;
final Compiler compiler = compilation.compiler;
if (isOnConflict)
compiler.compileInsertOnConflict(columns, select, onConflictColumns, doUpdate, compilation);
else if (select != null)
compiler.compileInsertSelect(columns, select, false, compilation);
else
compiler.compileInsert(columns, false, compilation);
}
}
static final class Update extends Command.Modification implements SET, keyword.Update.UPDATE_NOTIFY {
private ArrayList sets;
private Condition> where;
Update(final data.Table entity) {
super(entity);
}
@Override
public keyword.Update.UPDATE_NOTIFY onNotify(final OnNotify onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
@Override
public keyword.Update.UPDATE_NOTIFY onNotify(final boolean onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
private void initSets() {
if (sets == null)
sets = new ArrayList<>();
}
@Override
public SET SET(final data.Column extends T> column, final type.Column extends T> to) {
initSets();
sets.add(column);
sets.add((Subject)to);
return this;
}
@Override
public SET SET(final data.Column column, final T to) {
initSets();
sets.add(column);
// FIXME: data.ENUM.NULL
sets.add(to == null ? null : data.wrap(to));
return this;
}
@Override
public UPDATE WHERE(final Condition> condition) {
this.where = condition;
return this;
}
@Override
final data.Table getTable() {
return entity;
}
@Override
final data.Column> getColumn() {
throw new UnsupportedOperationException();
}
@Override
final void compile(final Compilation compilation, final boolean isExpression) throws IOException, SQLException {
final Compiler compiler = compilation.compiler;
if (sets != null)
compiler.compileUpdate(entity, sets, where, compilation);
else
compiler.compileUpdate(entity, compilation);
}
}
static final class Delete extends Command.Modification implements _DELETE, keyword.Delete.DELETE_NOTIFY {
private Condition> where;
Delete(final data.Table entity) {
super(entity);
}
@Override
public keyword.Delete.DELETE_NOTIFY onNotify(final OnNotify onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
@Override
public keyword.Delete.DELETE_NOTIFY onNotify(final boolean onNotify) {
if (sessionId == null)
sessionId = UUIDs.toString32(UUID.randomUUID());
getCallbacks().addOnNotify(sessionId, onNotify);
return this;
}
@Override
public DELETE WHERE(final Condition> where) {
this.where = where;
return this;
}
@Override
final data.Table getTable() {
return entity;
}
@Override
final data.Column> getColumn() {
return where;
}
@Override
void compile(final Compilation compilation, final boolean isExpression) throws IOException, SQLException {
final Compiler compiler = compilation.compiler;
if (where != null)
compiler.compileDelete(entity, where, compilation);
else
compiler.compileDelete(entity, compilation);
}
}
static final class Select {
public static class untyped {
abstract static class SELECT extends Command> implements keyword.Select.untyped._SELECT, keyword.Select.untyped.FROM, keyword.Select.untyped.GROUP_BY, keyword.Select.untyped.HAVING, keyword.Select.untyped.UNION, keyword.Select.untyped.JOIN, keyword.Select.untyped.ADV_JOIN, keyword.Select.untyped.ON, keyword.Select.untyped.ORDER_BY, keyword.Select.untyped.LIMIT, keyword.Select.untyped.OFFSET, keyword.Select.untyped.FOR, keyword.Select.untyped.NOWAIT, keyword.Select.untyped.SKIP_LOCKED, keyword.Select.untyped.WHERE {
enum LockStrength {
SHARE,
UPDATE
}
enum LockOption {
NOWAIT("NOWAIT"),
SKIP_LOCKED("SKIP LOCKED");
private final String name;
private LockOption(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
enum JoinKind {
INNER(""),
CROSS(" CROSS"),
NATURAL(" NATURAL"),
LEFT(" LEFT OUTER"),
RIGHT(" RIGHT OUTER"),
FULL(" FULL OUTER");
private final String keyword;
private JoinKind(final String keyword) {
this.keyword = keyword;
}
@Override
public String toString() {
return keyword;
}
}
private boolean tableCalled;
private data.Table table;
final boolean distinct;
final type.Entity[] entities;
private boolean fromCalled;
private data.Table[] from;
ArrayList joins;
ArrayList> on;
data.Entity[] groupBy;
Condition> having;
ArrayList unions;
data.Column>[] orderBy;
int[] orderByIndexes;
int limit = -1;
int offset = -1;
LockStrength forLockStrength;
Subject[] forSubjects;
LockOption forLockOption;
private boolean isObjectQuery;
private boolean whereCalled;
private Condition> where;
boolean isEntityOnlySelect;
boolean isConditionalSelect = false;
SELECT(final boolean distinct, final type.Entity[] entities) {
if (entities.length < 1)
throw new IllegalArgumentException("entities.length < 1");
assertNotNullArray(entities, "Argument to SELECT cannot be null (use type.?.NULL instead)");
this.entities = entities;
this.distinct = distinct;
}
@Override
public D AS(final D as) {
((data.Entity)as).wrap(new As(this, as, true));
return as;
}
@Override
public SELECT FROM(final data.Table ... from) {
this.from = from;
fromCalled = true;
return this;
}
@Override
public SELECT CROSS_JOIN(final data.Table table) {
return JOIN(JoinKind.CROSS, table);
}
@Override
public SELECT CROSS_JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.CROSS, select);
}
@Override
public SELECT NATURAL_JOIN(final data.Table table) {
return JOIN(JoinKind.NATURAL, table);
}
@Override
public SELECT NATURAL_JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.NATURAL, select);
}
@Override
public SELECT LEFT_JOIN(final data.Table table) {
return JOIN(JoinKind.LEFT, table);
}
@Override
public SELECT LEFT_JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.LEFT, select);
}
@Override
public SELECT RIGHT_JOIN(final data.Table table) {
return JOIN(JoinKind.RIGHT, table);
}
@Override
public SELECT RIGHT_JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.RIGHT, select);
}
@Override
public SELECT FULL_JOIN(final data.Table table) {
return JOIN(JoinKind.FULL, table);
}
@Override
public SELECT FULL_JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.FULL, select);
}
@Override
public SELECT JOIN(final data.Table table) {
return JOIN(JoinKind.INNER, table);
}
@Override
public SELECT JOIN(final keyword.Select.untyped.SELECT> select) {
return JOIN(JoinKind.INNER, select);
}
private SELECT JOIN(final JoinKind kind, final Object join) {
ArrayList joins = this.joins;
if (joins == null)
joins = this.joins = new ArrayList<>();
joins.add(kind);
joins.add(join);
return this;
}
@Override
public SELECT ON(final Condition> on) {
if (this.on == null)
this.on = new ArrayList<>();
// Since ON is optional, for each JOIN without ON, add a null to this.on
for (int i = 0, joinsSize = this.joins.size(), onSize = this.on.size(); i < joinsSize / 2 - onSize - 1; ++i) // [N]
this.on.add(null);
this.on.add(on);
return this;
}
@Override
public SELECT GROUP_BY(final data.Entity ... groupBy) {
this.groupBy = groupBy;
return this;
}
@Override
public SELECT HAVING(final Condition> having) {
this.having = having;
return this;
}
@Override
public SELECT UNION(final keyword.Select.untyped.SELECT select) {
UNION(Boolean.FALSE, select);
return this;
}
@Override
public SELECT UNION_ALL(final keyword.Select.untyped.SELECT select) {
UNION(Boolean.TRUE, select);
return this;
}
private SELECT UNION(final Boolean all, final keyword.Select.untyped.SELECT select) {
if (this.unions == null)
this.unions = new ArrayList<>();
this.unions.add(all);
this.unions.add(select);
return this;
}
@Override
public SELECT ORDER_BY(final data.Column> ... columns) {
this.orderBy = columns;
return this;
}
@Override
public SELECT LIMIT(final int rows) {
this.limit = rows;
return this;
}
@Override
public SELECT OFFSET(final int rows) {
this.offset = rows;
return this;
}
@Override
public SELECT FOR_SHARE(final data.Entity ... subjects) {
return FOR(LockStrength.SHARE, subjects);
}
@Override
public SELECT FOR_UPDATE(final data.Entity ... subjects) {
return FOR(LockStrength.UPDATE, subjects);
}
private SELECT FOR(final LockStrength lockStrength, final data.Entity ... subjects) {
this.forLockStrength = lockStrength;
this.forSubjects = subjects;
return this;
}
@Override
public SELECT NOWAIT() {
this.forLockOption = LockOption.NOWAIT;
return this;
}
@Override
public SELECT SKIP_LOCKED() {
this.forLockOption = LockOption.SKIP_LOCKED;
return this;
}
@Override
public SELECT WHERE(final Condition> where) {
this.where = where;
return this;
}
data.Column>[] getPrimaryColumnsFromCondition(final Condition> condition) {
final ArrayList> columns = new ArrayList<>(); // FIXME: Is there a way to do this without an ArrayList?
condition.collectColumns(columns);
return columns.toArray(new data.Column>[columns.size()]);
}
private Object[][] compile(final type.Entity[] entities, final int length, final int index, final int depth) {
if (index == length)
return new Object[depth][2];
final type.Entity entity = entities[index];
if (entity instanceof data.Table) {
final data.Table table = (data.Table)entity;
final int noColumns = table._column$.length;
final Object[][] protoSubjectIndexes = compile(entities, length, index + 1, depth + noColumns);
for (int i = 0; i < noColumns; ++i) { // [A]
final Object[] array = protoSubjectIndexes[depth + i];
array[0] = table._column$[i];
array[1] = i;
}
return protoSubjectIndexes;
}
if (entity instanceof type.Column) {
isEntityOnlySelect = false;
final type.Column> column = (type.Column>)entity;
final Object[][] protoSubjectIndexes = compile(entities, length, index + 1, depth + 1);
final Object[] array = protoSubjectIndexes[depth];
array[0] = column;
array[1] = -1;
return protoSubjectIndexes;
}
if (entity instanceof untyped.SELECT) {
isEntityOnlySelect = false;
final type.Entity[] selectEntities = ((untyped.SELECT>)entity).entities;
if (selectEntities.length != 1)
throw new IllegalStateException("Expected 1 entity, but got " + selectEntities.length);
final type.Entity selectEntity = selectEntities[0];
if (!(selectEntity instanceof data.Column))
throw new IllegalStateException("Expected data.Column, but got: " + selectEntity.getClass().getName());
final Object[][] protoSubjectIndexes = compile(entities, length, index + 1, depth + 1);
final Object[] array = protoSubjectIndexes[depth];
array[0] = selectEntity;
array[1] = -1;
return protoSubjectIndexes;
}
throw new IllegalStateException("Unknown entity type: " + entity.getClass().getName());
}
void assertRowIteratorConsumed(final boolean endReached, final boolean isCacheable, final SQLException e, final boolean isCacheableRowIteratorFullConsume) throws SQLException {
if (!endReached && isCacheable && isCacheableRowIteratorFullConsume) {
final IllegalStateException ie = new IllegalStateException("RowIterator end not reached for cacheableRowIteratorFullConsume=true");
if (e != null)
ie.addSuppressed(e);
throw ie;
}
if (e != null)
throw SQLExceptions.toStrongType(e);
}
@SuppressWarnings("unchecked")
RowIterator execute(final Schema schema, final Transaction transaction, Connector connector, Connection connection, boolean isPrepared, final Transaction.Isolation isolation, final QueryConfig contextQueryConfig) throws IOException, SQLException {
assertNotClosed();
Statement statement = null;
try {
if (transaction != null) {
isPrepared = transaction.isPrepared();
connection = transaction.getConnection();
}
else if (connection == null) {
if (connector == null)
connector = schema.getConnector();
isPrepared = connector.isPrepared();
connection = connector.getConnection(isolation);
connection.setAutoCommit(true);
}
final DbVendor vendor = DbVendor.valueOf(connection.getMetaData());
try (final Compilation compilation = new Compilation(this, vendor, isPrepared)) {
final QueryConfig defaultQueryConfig = schema.defaultQueryConfig;
isEntityOnlySelect = true;
final Object[][] protoSubjectIndexes = compile(entities, entities.length, 0, 0);
final boolean cacheSelectEntity = QueryConfig.getCacheSelectEntity(contextQueryConfig, defaultQueryConfig);
compile(compilation, false, cacheSelectEntity);
final Notifier> notifier;
final boolean isSelectAll;
if (cacheSelectEntity) {
notifier = schema.getCacheNotifier();
isSelectAll = isEntityOnlySelect && !isConditionalSelect;
}
else {
notifier = null;
isSelectAll = false;
}
final int columnOffset = compilation.skipFirstColumn() ? 2 : 1;
final Compiler compiler = compilation.compiler;
final ResultSet resultSet = QueryConfig.executeQuery(contextQueryConfig, defaultQueryConfig, compilation, connection);
if (callbacks != null)
callbacks.onExecute(Statement.SUCCESS_NO_INFO);
final Connector connectorFinal = connector;
final Connection connectionFinal = connection;
final Statement statementFinal = statement = resultSet.getStatement();
final int noColumns = resultSet.getMetaData().getColumnCount() + 1 - columnOffset;
return new RowIterator(resultSet, contextQueryConfig, defaultQueryConfig) {
private final boolean isCacheableRowIteratorFullConsume = QueryConfig.getCacheableRowIteratorFullConsume(contextQueryConfig, defaultQueryConfig);
private HashMap,data.Table> prototypes = new HashMap<>();
private HashMap cachedTables = new HashMap<>();
private data.Table currentTable;
private boolean mustFetchRow = false;
@Override
public boolean nextRow() throws SQLException {
if (endReached)
return false;
try {
if (endReached = !resultSet.next()) {
if (isSelectAll)
table._commitSelectAll$();
return false;
}
mustFetchRow = true;
}
catch (SQLException e) {
e = Throwables.addSuppressed(e, suppressed);
suppressed = null;
throw SQLExceptions.toStrongType(e);
}
return true;
}
@Override
public D nextEntity() throws SQLException {
fetchRow();
return super.nextEntity();
}
private void onSelect(final data.Table row) {
if (notifier != null && row.getCacheSelectEntity())
notifier.onSelect(row);
}
@SuppressWarnings("null")
private void fetchRow() throws SQLException {
if (!mustFetchRow)
return;
final type.Entity[] row;
int index = 0;
data.Table table;
try {
row = new type.Entity[entities.length];
table = null;
for (int i = 0; i < noColumns; ++i) { // [A]
final Object[] protoSubjectIndex = protoSubjectIndexes[i];
final Subject protoSubject = (Subject)protoSubjectIndex[0];
final Integer protoIndex = (Integer)protoSubjectIndex[1];
if (currentTable != null && (currentTable != protoSubject.getTable() || protoIndex == -1)) {
data.Table cachedTable = cachedTables.get(table);
if (cachedTable == null) {
cachedTables.put(table, cachedTable = table);
prototypes.put(table.getClass(), table.newInstance());
}
row[index++] = cachedTable;
onSelect(cachedTable);
}
final data.Column> column;
if (protoIndex != -1) {
currentTable = protoSubject.getTable();
if (currentTable._mutable$) {
table = currentTable;
}
else {
table = prototypes.get(currentTable.getClass());
if (table == null)
prototypes.put(currentTable.getClass(), table = currentTable.newInstance());
}
column = table._column$[protoIndex];
}
else {
table = null;
currentTable = null;
if (protoSubject instanceof data.Column) {
final data.Column> col = (data.Column>)protoSubject;
column = col._mutable$ ? col : col.clone();
}
else {
column = protoSubject.getColumn().clone();
}
row[index++] = column;
}
column.read(compiler, resultSet, i + columnOffset);
}
}
catch (SQLException e) {
e = Throwables.addSuppressed(e, suppressed);
suppressed = null;
throw SQLExceptions.toStrongType(e);
}
if (table != null) {
final data.Table cachedTable = cachedTables.getOrDefault(table, table);
row[index++] = cachedTable;
onSelect(cachedTable);
}
setRow((D[])row);
prototypes.clear();
currentTable = null;
mustFetchRow = false;
}
@Override
public void close() throws SQLException {
SQLException e = Throwables.addSuppressed(suppressed, ResultSets.close(resultSet));
e = Throwables.addSuppressed(e, AuditStatement.close(statementFinal));
if (connectorFinal != null)
e = Throwables.addSuppressed(e, AuditConnection.close(connectionFinal));
prototypes = null;
cachedTables = null;
currentTable = null;
assertRowIteratorConsumed(endReached, isEntityOnlySelect, e, isCacheableRowIteratorFullConsume);
}
};
}
}
catch (SQLException e) {
if (statement != null)
e = Throwables.addSuppressed(e, AuditStatement.close(statement));
if (connector != null)
e = Throwables.addSuppressed(e, AuditConnection.close(connection));
throw SQLExceptions.toStrongType(e);
}
finally {
close();
}
}
@Override
public final RowIterator execute(final Transaction transaction) throws IOException, SQLException {
return execute(getSchema(), transaction, null, null, false, null, null);
}
@Override
public final RowIterator execute(final Connector connector, final Transaction.Isolation isolation) throws IOException, SQLException {
return execute(getSchema(), null, connector, null, false, isolation, null);
}
@Override
public final RowIterator execute(final Connector connector) throws IOException, SQLException {
return execute(getSchema(), null, connector, null, false, null, null);
}
@Override
public final RowIterator execute(final Connection connection, final boolean isPrepared) throws IOException, SQLException {
return execute(getSchema(), null, null, assertNotNull(connection), isPrepared, null, null);
}
@Override
public final RowIterator execute(final Transaction.Isolation isolation) throws IOException, SQLException {
final Schema schema = getSchema();
return execute(schema, null, null, null, false, isolation, null);
}
@Override
public RowIterator execute() throws IOException, SQLException {
final Schema schema = getSchema();
return execute(schema, null, null, null, false, null, null);
}
@Override
public final RowIterator execute(final Transaction transaction, final QueryConfig config) throws IOException, SQLException {
return execute(getSchema(), transaction, null, null, false, null, config);
}
@Override
public final RowIterator execute(final Connector connector, final Transaction.Isolation isolation, final QueryConfig config) throws IOException, SQLException {
return execute(getSchema(), null, connector, null, false, isolation, config);
}
@Override
public final RowIterator execute(final Connector connector, final QueryConfig config) throws IOException, SQLException {
return execute(getSchema(), null, connector, null, false, null, config);
}
@Override
public final RowIterator execute(final Connection connection, final boolean isPrepared, final QueryConfig config) throws IOException, SQLException {
return execute(getSchema(), null, null, assertNotNull(connection), isPrepared, null, null);
}
@Override
public final RowIterator execute(final Transaction.Isolation isolation, final QueryConfig config) throws IOException, SQLException {
final Schema schema = getSchema();
return execute(schema, null, null, null, false, isolation, config);
}
@Override
public RowIterator execute(final QueryConfig config) throws IOException, SQLException {
final Schema schema = getSchema();
return execute(schema, null, null, null, false, null, null);
}
@Override
final data.Table getTable() {
if (tableCalled)
return table;
tableCalled = true;
// FIXME: Note that this returns the 1st table only! Is this what we want?!
if (entities[0] instanceof Select.untyped.SELECT)
return table = ((Select.untyped.SELECT>)entities[0]).getTable();
final data.Table[] from = from();
return from != null ? table = from[0] : null;
}
@Override
final data.Column> getColumn() {
if (entities.length == 1)
return ((Subject)entities[0]).getColumn();
throw new UnsupportedOperationException();
}
// FIXME: What is translateTypes for again?
HashMap> translateTypes;
data.Table[] from() {
if (fromCalled)
return from;
fromCalled = true;
from = getTables(entities, entities.length, 0, 0);
if ((isObjectQuery = where == null) || from == null)
for (final type.Entity entity : entities) // [A]
isObjectQuery &= entity instanceof data.Table;
return from;
}
private static data.Table[] getTables(final type.Entity[] subjects, final int length, final int index, final int depth) {
if (index == length)
return depth == 0 ? null : new data.Table[depth];
final type.Entity entity = subjects[index];
final data.Table table = ((Subject)entity).getTable();
if (table == null)
return getTables(subjects, length, index + 1, depth);
final data.Table[] tables = getTables(subjects, length, index + 1, depth + 1);
tables[depth] = table;
return tables;
}
Condition> where() {
if (whereCalled)
return where;
whereCalled = true;
if (isObjectQuery) {
final Condition>[] conditions = createObjectQueryConditions(entities, entities.length, 0, 0);
if (conditions != null)
where = conditions.length == 1 ? conditions[0] : DML.AND(conditions);
}
isConditionalSelect = where != null;
return where;
}
private static Condition>[] createObjectQueryConditions(final type.Entity[] entities, final int length, final int index, final int depth) {
if (index == length)
return depth == 0 ? null : new Condition[depth];
final type.Entity entity = entities[index];
if (entity instanceof data.Table) {
final data.Column>[] columns = ((data.Table)entity)._column$;
final Condition>[] columnConditions = createObjectQueryConditions(columns, columns.length, 0, 0);
if (columnConditions == null)
return createObjectQueryConditions(entities, length, index + 1, depth);
final Condition>[] entityConditions = createObjectQueryConditions(entities, length, index + 1, depth + 1);
entityConditions[depth] = columnConditions.length == 1 ? columnConditions[0] : DML.AND(columnConditions);
return entityConditions;
}
else if (entity instanceof Select.untyped.SELECT) {
return createObjectQueryConditions(entities, length, index + 1, depth);
}
throw new UnsupportedOperationException("Unsupported entity of object query: " + entity.getClass().getName());
}
private static Condition>[] createObjectQueryConditions(final data.Column>[] columns, final int length, final int index, final int depth) {
if (index == length)
return depth == 0 ? null : new Condition[depth];
final data.Column> column = columns[index];
final boolean wasSet = column.setByCur == data.Column.SetBy.USER || (column.primaryIndexType != null || column.isKeyForUpdate) && column.setByCur == data.Column.SetBy.SYSTEM;
if (!wasSet)
return createObjectQueryConditions(columns, length, index + 1, depth);
final Condition>[] conditions = createObjectQueryConditions(columns, length, index + 1, depth + 1);
conditions[depth] = new ComparisonPredicate.Eq<>(column, column.get());
return conditions;
}
@Override
final void compile(final Compilation compilation, final boolean isExpression) throws IOException, SQLException {
final Compiler compiler = compilation.compiler;
final boolean useAliases = forLockStrength == null || forSubjects == null || forSubjects.length == 0 || compiler.aliasInForUpdate();
compiler.assignAliases(from(), joins, compilation);
compiler.compileSelect(this, useAliases, compilation);
compiler.compileFrom(from, useAliases, compilation);
if (joins != null)
for (int i = 0, j = 0, i$ = joins.size(), j$ = on == null ? Integer.MIN_VALUE : on.size(); i < i$; j = i / 2) // [RA]
compiler.compileJoin((JoinKind)joins.get(i++), joins.get(i++), j < j$ ? on.get(j) : null, compilation);
compiler.compileWhere(where(), compilation);
compiler.compileGroupByHaving(this, useAliases, compilation);
compiler.compileUnion(this, compilation);
compiler.compileOrderBy(this, compilation);
compiler.compileLimitOffset(this, compilation);
if (forLockStrength != null)
compiler.compileFor(this, compilation);
}
void compile(final Compilation compilation, final boolean isExpression, final boolean cacheSelectEntity) throws IOException, SQLException {
compile(compilation, isExpression);
if (cacheSelectEntity && !isEntityOnlySelect)
throw new IllegalStateException("QueryConfig.cacheSelectEntity=true can only be fulfilled for queries that exclusively select entities instead of individual columns");
}
}
}
public static class ARRAY {
static class SELECT extends untyped.SELECT implements keyword.Select.ARRAY._SELECT, keyword.Select.ARRAY.FROM, keyword.Select.ARRAY.GROUP_BY, keyword.Select.ARRAY.HAVING, keyword.Select.ARRAY.UNION, keyword.Select.ARRAY.JOIN, keyword.Select.ARRAY.ADV_JOIN, keyword.Select.ARRAY.ON, keyword.Select.ARRAY.ORDER_BY, keyword.Select.ARRAY.LIMIT, keyword.Select.ARRAY.OFFSET, keyword.Select.ARRAY.FOR, keyword.Select.ARRAY.NOWAIT, keyword.Select.ARRAY.SKIP_LOCKED, keyword.Select.ARRAY.WHERE {
SELECT(final boolean distinct, final type.Entity[] entities) {
super(distinct, entities);
}
@Override
public D AS(final D as) {
((data.Entity)as).wrap(new As(this, as, true));
return as;
}
@Override
public final SELECT FROM(final data.Table ... from) {
super.FROM(from);
return this;
}
@Override
public final SELECT CROSS_JOIN(final data.Table table) {
super.CROSS_JOIN(table);
return this;
}
@Override
public final SELECT CROSS_JOIN(final keyword.Select.untyped.SELECT> select) {
super.CROSS_JOIN(select);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final data.Table table) {
super.NATURAL_JOIN(table);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.NATURAL_JOIN(select);
return this;
}
@Override
public final SELECT LEFT_JOIN(final data.Table table) {
super.LEFT_JOIN(table);
return this;
}
@Override
public final SELECT LEFT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.LEFT_JOIN(select);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final data.Table table) {
super.RIGHT_JOIN(table);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.RIGHT_JOIN(select);
return this;
}
@Override
public final SELECT FULL_JOIN(final data.Table table) {
super.FULL_JOIN(table);
return this;
}
@Override
public final SELECT FULL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.FULL_JOIN(select);
return this;
}
@Override
public final SELECT JOIN(final data.Table table) {
super.JOIN(table);
return this;
}
@Override
public final SELECT JOIN(final keyword.Select.untyped.SELECT> select) {
super.JOIN(select);
return this;
}
@Override
public final SELECT ON(final Condition> on) {
super.ON(on);
return this;
}
@Override
public final SELECT GROUP_BY(final data.Entity ... groupBy) {
super.GROUP_BY(groupBy);
return this;
}
@Override
public final SELECT HAVING(final Condition> having) {
super.HAVING(having);
return this;
}
@Override
public final SELECT UNION(final keyword.Select.ARRAY.SELECT select) {
super.UNION(select);
return this;
}
@Override
public final SELECT UNION_ALL(final keyword.Select.ARRAY.SELECT select) {
super.UNION_ALL(select);
return this;
}
@Override
public final SELECT ORDER_BY(final data.Column> ... columns) {
super.ORDER_BY(columns);
return this;
}
@Override
public final SELECT LIMIT(final int rows) {
super.LIMIT(rows);
return this;
}
@Override
public final SELECT OFFSET(final int rows) {
super.OFFSET(rows);
return this;
}
@Override
public final SELECT FOR_SHARE(final data.Entity ... subjects) {
super.FOR_SHARE(subjects);
return this;
}
@Override
public final SELECT FOR_UPDATE(final data.Entity ... subjects) {
super.FOR_UPDATE(subjects);
return this;
}
@Override
public final SELECT NOWAIT() {
super.NOWAIT();
return this;
}
@Override
public final SELECT SKIP_LOCKED() {
super.SKIP_LOCKED();
return this;
}
@Override
public final SELECT WHERE(final Condition> where) {
super.WHERE(where);
return this;
}
}
}
public static class BIGINT {
static class SELECT extends untyped.SELECT implements keyword.Select.BIGINT._SELECT, keyword.Select.BIGINT.FROM, keyword.Select.BIGINT.GROUP_BY, keyword.Select.BIGINT.HAVING, keyword.Select.BIGINT.UNION, keyword.Select.BIGINT.JOIN, keyword.Select.BIGINT.ADV_JOIN, keyword.Select.BIGINT.ON, keyword.Select.BIGINT.ORDER_BY, keyword.Select.BIGINT.LIMIT, keyword.Select.BIGINT.OFFSET, keyword.Select.BIGINT.FOR, keyword.Select.BIGINT.NOWAIT, keyword.Select.BIGINT.SKIP_LOCKED, keyword.Select.BIGINT.WHERE {
SELECT(final boolean distinct, final type.Entity[] entities) {
super(distinct, entities);
}
@Override
public D AS(final D as) {
((data.Entity)as).wrap(new As(this, as, true));
return as;
}
@Override
public final SELECT FROM(final data.Table ... from) {
super.FROM(from);
return this;
}
@Override
public final SELECT CROSS_JOIN(final data.Table table) {
super.CROSS_JOIN(table);
return this;
}
@Override
public final SELECT CROSS_JOIN(final keyword.Select.untyped.SELECT> select) {
super.CROSS_JOIN(select);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final data.Table table) {
super.NATURAL_JOIN(table);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.NATURAL_JOIN(select);
return this;
}
@Override
public final SELECT LEFT_JOIN(final data.Table table) {
super.LEFT_JOIN(table);
return this;
}
@Override
public final SELECT LEFT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.LEFT_JOIN(select);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final data.Table table) {
super.RIGHT_JOIN(table);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.RIGHT_JOIN(select);
return this;
}
@Override
public final SELECT FULL_JOIN(final data.Table table) {
super.FULL_JOIN(table);
return this;
}
@Override
public final SELECT FULL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.FULL_JOIN(select);
return this;
}
@Override
public final SELECT JOIN(final data.Table table) {
super.JOIN(table);
return this;
}
@Override
public final SELECT JOIN(final keyword.Select.untyped.SELECT> select) {
super.JOIN(select);
return this;
}
@Override
public final SELECT ON(final Condition> on) {
super.ON(on);
return this;
}
@Override
public final SELECT GROUP_BY(final data.Entity ... groupBy) {
super.GROUP_BY(groupBy);
return this;
}
@Override
public final SELECT HAVING(final Condition> having) {
super.HAVING(having);
return this;
}
@Override
public final SELECT UNION(final keyword.Select.BIGINT.SELECT select) {
super.UNION(select);
return this;
}
@Override
public final SELECT UNION_ALL(final keyword.Select.BIGINT.SELECT select) {
super.UNION_ALL(select);
return this;
}
@Override
public final SELECT ORDER_BY(final data.Column> ... columns) {
super.ORDER_BY(columns);
return this;
}
@Override
public final SELECT LIMIT(final int rows) {
super.LIMIT(rows);
return this;
}
@Override
public final SELECT OFFSET(final int rows) {
super.OFFSET(rows);
return this;
}
@Override
public final SELECT FOR_SHARE(final data.Entity ... subjects) {
super.FOR_SHARE(subjects);
return this;
}
@Override
public final SELECT FOR_UPDATE(final data.Entity ... subjects) {
super.FOR_UPDATE(subjects);
return this;
}
@Override
public final SELECT NOWAIT() {
super.NOWAIT();
return this;
}
@Override
public final SELECT SKIP_LOCKED() {
super.SKIP_LOCKED();
return this;
}
@Override
public final SELECT WHERE(final Condition> where) {
super.WHERE(where);
return this;
}
}
}
public static class BINARY {
static class SELECT extends untyped.SELECT implements keyword.Select.BINARY._SELECT, keyword.Select.BINARY.FROM, keyword.Select.BINARY.GROUP_BY, keyword.Select.BINARY.HAVING, keyword.Select.BINARY.UNION, keyword.Select.BINARY.JOIN, keyword.Select.BINARY.ADV_JOIN, keyword.Select.BINARY.ON, keyword.Select.BINARY.ORDER_BY, keyword.Select.BINARY.LIMIT, keyword.Select.BINARY.OFFSET, keyword.Select.BINARY.FOR, keyword.Select.BINARY.NOWAIT, keyword.Select.BINARY.SKIP_LOCKED, keyword.Select.BINARY.WHERE {
SELECT(final boolean distinct, final type.Entity[] entities) {
super(distinct, entities);
}
@Override
public D AS(final D as) {
((data.Entity)as).wrap(new As(this, as, true));
return as;
}
@Override
public final SELECT FROM(final data.Table ... from) {
super.FROM(from);
return this;
}
@Override
public final SELECT CROSS_JOIN(final data.Table table) {
super.CROSS_JOIN(table);
return this;
}
@Override
public final SELECT CROSS_JOIN(final keyword.Select.untyped.SELECT> select) {
super.CROSS_JOIN(select);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final data.Table table) {
super.NATURAL_JOIN(table);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.NATURAL_JOIN(select);
return this;
}
@Override
public final SELECT LEFT_JOIN(final data.Table table) {
super.LEFT_JOIN(table);
return this;
}
@Override
public final SELECT LEFT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.LEFT_JOIN(select);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final data.Table table) {
super.RIGHT_JOIN(table);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.RIGHT_JOIN(select);
return this;
}
@Override
public final SELECT FULL_JOIN(final data.Table table) {
super.FULL_JOIN(table);
return this;
}
@Override
public final SELECT FULL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.FULL_JOIN(select);
return this;
}
@Override
public final SELECT JOIN(final data.Table table) {
super.JOIN(table);
return this;
}
@Override
public final SELECT JOIN(final keyword.Select.untyped.SELECT> select) {
super.JOIN(select);
return this;
}
@Override
public final SELECT ON(final Condition> on) {
super.ON(on);
return this;
}
@Override
public final SELECT GROUP_BY(final data.Entity ... groupBy) {
super.GROUP_BY(groupBy);
return this;
}
@Override
public final SELECT HAVING(final Condition> having) {
super.HAVING(having);
return this;
}
@Override
public final SELECT UNION(final keyword.Select.BINARY.SELECT select) {
super.UNION(select);
return this;
}
@Override
public final SELECT UNION_ALL(final keyword.Select.BINARY.SELECT select) {
super.UNION_ALL(select);
return this;
}
@Override
public final SELECT ORDER_BY(final data.Column> ... columns) {
super.ORDER_BY(columns);
return this;
}
@Override
public final SELECT LIMIT(final int rows) {
super.LIMIT(rows);
return this;
}
@Override
public final SELECT OFFSET(final int rows) {
super.OFFSET(rows);
return this;
}
@Override
public final SELECT FOR_SHARE(final data.Entity ... subjects) {
super.FOR_SHARE(subjects);
return this;
}
@Override
public final SELECT FOR_UPDATE(final data.Entity ... subjects) {
super.FOR_UPDATE(subjects);
return this;
}
@Override
public final SELECT NOWAIT() {
super.NOWAIT();
return this;
}
@Override
public final SELECT SKIP_LOCKED() {
super.SKIP_LOCKED();
return this;
}
@Override
public final SELECT WHERE(final Condition> where) {
super.WHERE(where);
return this;
}
}
}
public static class BLOB {
static class SELECT extends untyped.SELECT implements keyword.Select.BLOB._SELECT, keyword.Select.BLOB.FROM, keyword.Select.BLOB.GROUP_BY, keyword.Select.BLOB.HAVING, keyword.Select.BLOB.UNION, keyword.Select.BLOB.JOIN, keyword.Select.BLOB.ADV_JOIN, keyword.Select.BLOB.ON, keyword.Select.BLOB.ORDER_BY, keyword.Select.BLOB.LIMIT, keyword.Select.BLOB.OFFSET, keyword.Select.BLOB.FOR, keyword.Select.BLOB.NOWAIT, keyword.Select.BLOB.SKIP_LOCKED, keyword.Select.BLOB.WHERE {
SELECT(final boolean distinct, final type.Entity[] entities) {
super(distinct, entities);
}
@Override
public D AS(final D as) {
((data.Entity)as).wrap(new As(this, as, true));
return as;
}
@Override
public final SELECT FROM(final data.Table ... from) {
super.FROM(from);
return this;
}
@Override
public final SELECT CROSS_JOIN(final data.Table table) {
super.CROSS_JOIN(table);
return this;
}
@Override
public final SELECT CROSS_JOIN(final keyword.Select.untyped.SELECT> select) {
super.CROSS_JOIN(select);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final data.Table table) {
super.NATURAL_JOIN(table);
return this;
}
@Override
public final SELECT NATURAL_JOIN(final keyword.Select.untyped.SELECT> select) {
super.NATURAL_JOIN(select);
return this;
}
@Override
public final SELECT LEFT_JOIN(final data.Table table) {
super.LEFT_JOIN(table);
return this;
}
@Override
public final SELECT LEFT_JOIN(final keyword.Select.untyped.SELECT> select) {
super.LEFT_JOIN(select);
return this;
}
@Override
public final SELECT RIGHT_JOIN(final data.Table table) {
super.RIGHT_JOIN(table);
return this;
}
@Override
public final SELECT