io.army.dialect.postgre.PostgreDialectParser Maven / Gradle / Ivy
package io.army.dialect.postgre;
import io.army.criteria.*;
import io.army.criteria.impl.Postgres;
import io.army.criteria.impl.SQLs;
import io.army.criteria.impl._JoinType;
import io.army.criteria.impl._PostgreConsultant;
import io.army.criteria.impl.inner.*;
import io.army.criteria.impl.inner.postgre.*;
import io.army.dialect.*;
import javax.annotation.Nullable;
import io.army.meta.SingleTableMeta;
import io.army.meta.TableMeta;
import io.army.modelgen._MetaBridge;
import io.army.util._Exceptions;
import io.army.util._StringUtils;
import java.util.List;
/**
*
* This class is the implementation of {@link DialectParser} for PostgreSQL dialect criteria api.
*
* Below is chinese signature:
* 当你在阅读这段代码时,我才真正在写这段代码,你阅读到哪里,我便写到哪里.
*
* @since 1.0
*/
final class PostgreDialectParser extends PostgreParser {
static PostgreDialectParser create(DialectEnv environment, PostgreDialect dialect) {
return new PostgreDialectParser(environment, dialect);
}
private static final String SPACE_ON_CONFLICT = " ON CONFLICT";
private static final String SPACE_ON_CONSTRAINT = " ON CONSTRAINT";
private PostgreDialectParser(DialectEnv environment, PostgreDialect dialect) {
super(environment, dialect);
}
@Override
public String sqlElement(final SQLElement element) {
_PostgreConsultant.assertSqlElement(element);
if (!(element instanceof _TableNameElement)) {
throw _Exceptions.castCriteriaApi();
}
//TODO
return this.safeObjectName(((_TableNameElement) element).tableMeta());
}
@Override
protected void assertInsert(InsertStatement insert) {
_PostgreConsultant.assertInsert(insert);
}
@Override
protected void assertUpdate(UpdateStatement update) {
_PostgreConsultant.assertUpdate(update);
}
@Override
protected void assertDelete(DeleteStatement delete) {
_PostgreConsultant.assertDelete(delete);
}
@Override
protected void assertRowSet(final RowSet query) {
_PostgreConsultant.assertRowSet(query);
}
@Override
protected void parseClauseAfterRightParen(final _ParensRowSet rowSet, final _ParenRowSetContext context) {
this.orderByClause(rowSet.orderByList(), context);
postgreLimitClause((_Statement._SQL2008LimitClauseSpec) rowSet, context);
}
@Override
protected void parseWithClause(final _Statement._WithClauseSpec spec, final _SqlContext context) {
final List<_Cte> cteList = spec.cteList();
final int cteSize = cteList.size();
if (cteSize == 0) {
return;
}
final StringBuilder sqlBuilder;
if ((sqlBuilder = context.sqlBuilder()).length() > 0) {
sqlBuilder.append(_Constant.SPACE);
}
sqlBuilder.append(_Constant.WITH);
if (spec.isRecursive()) {
sqlBuilder.append(_Constant.SPACE_RECURSIVE);
}
_PostgreCte cte;
SubStatement subStatement;
List columnAliasList;
for (int i = 0, columnSize; i < cteSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA_SPACE);
} else {
sqlBuilder.append(_Constant.SPACE);
}
cte = (_PostgreCte) cteList.get(i);
this.identifier(cte.name(), sqlBuilder);
columnAliasList = cte.columnAliasList();
columnSize = columnAliasList.size();
if (columnSize > 0) {
sqlBuilder.append(_Constant.SPACE_LEFT_PAREN);
for (int columnIndex = 0; columnIndex < columnSize; columnIndex++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA_SPACE);
} else {
sqlBuilder.append(_Constant.SPACE);
}
this.identifier(columnAliasList.get(columnIndex), sqlBuilder);
}
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
}
sqlBuilder.append(_Constant.SPACE_AS)
.append(_Constant.SPACE_LEFT_PAREN);
subStatement = cte.subStatement();
if (subStatement instanceof SubQuery) {
this.handleQuery((SubQuery) subStatement, context);
} else if (subStatement instanceof _Insert) {
this.handleInsertStmt(context, (_Insert) subStatement, context.visible());
} else {
//TODO
throw new UnsupportedOperationException();
}
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
}
}
@Override
protected void parseValuesInsert(final _ValueSyntaxInsertContext context, final _Insert._ValuesSyntaxInsert insert) {
this.parsePostgreInsert(context, (_PostgreInsert) insert);
}
@Override
protected void parseQueryInsert(final _QueryInsertContext context, final _Insert._QueryInsert insert) {
this.parsePostgreInsert(context, (_PostgreInsert) insert);
}
@Override
protected void parseSimpleQuery(final _Query query, final _SimpleQueryContext context) {
final _PostgreQuery stmt = (_PostgreQuery) query;
// 1. WITH clause
this.parseWithClause(stmt, context);
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
if (sqlBuilder.length() > 0) {
sqlBuilder.append(_Constant.SPACE);
}
// 2. SELECT key word
sqlBuilder.append(_Constant.SELECT);
// 3. modifiers
this.selectModifierClause(stmt.modifierList(), context, _PostgreConsultant::queryModifier);
// 4. DISTINCT ON expression clause
distinctOnExpressionsClause(stmt, context);
// 5. selection list clause
this.selectionListClause(context);
// 6. FROM clause
final List<_TabularBlock> tableBlockList;
tableBlockList = stmt.tableBlockList();
if (tableBlockList.size() > 0) {
sqlBuilder.append(_Constant.SPACE_FROM);
this.postgreFromItemsClause(stmt.tableBlockList(), context, false);
}
// 7. WHERE clause
this.queryWhereClause(tableBlockList, stmt.wherePredicateList(), context);
// 8. GROUP BY and having clause
final List extends GroupByItem> groupByItemList;
final int groupItemSize;
if ((groupItemSize = (groupByItemList = stmt.groupByList()).size()) > 0) {
sqlBuilder.append(_Constant.SPACE_GROUP_BY);
final SQLs.Modifier modifier = stmt.groupByModifier();
if (modifier != null) {
sqlBuilder.append(modifier.spaceRender());
}
for (int i = 0; i < groupItemSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
((_SelfDescribed) groupByItemList.get(i)).appendSql(sqlBuilder, context);
}
this.havingClause(stmt.havingList(), context);
}
// 9. WINDOW clause
final List<_Window> windowList;
windowList = stmt.windowList();
if (windowList.size() > 0) {
this.windowClause(windowList, context, _PostgreConsultant::assertWindow);
}
// 10. ORDER BY clause
this.orderByClause(stmt.orderByList(), context);
// 11. LIMIT OFFSET FETCH clause
postgreLimitClause(stmt, context);
// 12 LOCK clause
postgreLockClause(stmt, context);
}
@Override
protected void parseSimpleValues(_ValuesQuery values, _ValuesContext context) {
super.parseSimpleValues(values, context);
}
@Override
protected void parseSingleUpdate(final _SingleUpdate update, final _SingleUpdateContext context) {
final _PostgreUpdate stmt = (_PostgreUpdate) update;
// 1. WITH clause
this.parseWithClause(stmt, context);
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
if (sqlBuilder.length() > 0) {
sqlBuilder.append(_Constant.SPACE);
}
// 2. UPDATE key word
sqlBuilder.append(_Constant.UPDATE);
// 3. ONLY modifier
final SQLWords onlyModifier;
onlyModifier = stmt.modifier();
if (onlyModifier != null) {
assert onlyModifier == SQLs.ONLY;
sqlBuilder.append(onlyModifier.spaceRender());
}
// 4. table name
sqlBuilder.append(_Constant.SPACE);
final TableMeta> updateTable = context.targetTable();
assert updateTable == stmt.table();
this.safeObjectName(updateTable, sqlBuilder);
// 5. table alias
final String safeTableAlias;
safeTableAlias = context.safeTargetTableAlias();
sqlBuilder.append(_Constant.SPACE_AS_SPACE)
.append(safeTableAlias);
// 6. SET clause
this.singleTableSetClause(stmt.itemPairList(), context);
// 7. FROM clause
final List<_TabularBlock> tableBlockList;
tableBlockList = stmt.tableBlockList();
final boolean existsFromClause;
existsFromClause = tableBlockList.size() > 0;
if (existsFromClause) {
sqlBuilder.append(_Constant.SPACE_FROM);
this.postgreFromItemsClause(stmt.tableBlockList(), (_MultiTableStmtContext) context, false);
}
// 8. WHERE clause
this.dmlWhereClause(stmt.wherePredicateList(), context);
context.appendConditionFields();
//TODO discriminator
if (existsFromClause) {
this.multiTableVisible(tableBlockList, (_MultiTableStmtContext) context, false);
} else if (updateTable instanceof SingleTableMeta) {
this.visiblePredicate((SingleTableMeta>) updateTable, safeTableAlias, context, false);
}
// 9. RETURNING clause
if (stmt instanceof _ReturningDml) {
returningClause(context, (_ReturningDml) stmt);
}
}
@Override
protected void parseSingleDelete(final _SingleDelete delete, final _SingleDeleteContext context) {
final _PostgreDelete stmt = (_PostgreDelete) delete;
// 1. WITH clause
this.parseWithClause(stmt, context);
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
if (sqlBuilder.length() > 0) {
sqlBuilder.append(_Constant.SPACE);
}
// 2. DELETE key word
sqlBuilder.append(_Constant.DELETE_FROM);
// 3. ONLY modifier
final SQLs.WordOnly onlyModifier;
onlyModifier = stmt.modifier();
if (onlyModifier != null) {
assert onlyModifier == SQLs.ONLY;
sqlBuilder.append(onlyModifier.spaceRender());
}
// 4. table name
final TableMeta> deleteTable = context.targetTable();
assert deleteTable == stmt.table();
sqlBuilder.append(_Constant.SPACE);
this.safeObjectName(deleteTable, sqlBuilder);
// 5. symbol star
final SQLs.SymbolAsterisk symbolStar;
if ((symbolStar = stmt.symbolAsterisk()) != null) {
assert symbolStar == SQLs.ASTERISK;
sqlBuilder.append(_Constant.SPACE)
.append(_Constant.ASTERISK);
}
// 6. table alias
final String safeTableAlias;
safeTableAlias = context.safeTargetTableAlias();
sqlBuilder.append(_Constant.SPACE_AS_SPACE)
.append(safeTableAlias);
// 7. USING clause
final List<_TabularBlock> tableBlockList;
tableBlockList = stmt.tableBlockList();
final boolean existsFromClause;
existsFromClause = tableBlockList.size() > 0;
if (existsFromClause) {
sqlBuilder.append(_Constant.SPACE_USING);
this.postgreFromItemsClause(stmt.tableBlockList(), (_MultiTableStmtContext) context, false);
}
// 8. WHERE clause
this.dmlWhereClause(stmt.wherePredicateList(), context);
//TODO discriminator
if (existsFromClause) {
this.multiTableVisible(tableBlockList, (_MultiTableStmtContext) context, false);
} else if (deleteTable instanceof SingleTableMeta) {
this.visiblePredicate((SingleTableMeta>) deleteTable, safeTableAlias, context, false);
}
// 9. RETURNING clause
if (stmt instanceof _ReturningDml) {
returningClause(context, (_ReturningDml) stmt);
}
}
@Override
protected _PrimaryContext handleDialectDml(@Nullable _SqlContext outerContext, DmlStatement statement,
Visible visible) {
return super.handleDialectDml(outerContext, statement, visible);
}
@Override
protected _PrimaryContext handleDialectDql(@Nullable _SqlContext outerContext, DqlStatement statement,
Visible visible) {
return super.handleDialectDql(outerContext, statement, visible);
}
/**
* @see #parseSimpleQuery(_Query, _SimpleQueryContext)
* @see #parseSingleUpdate(_SingleUpdate, _SingleUpdateContext)
* @see #parseSingleDelete(_SingleDelete, _SingleDeleteContext)
*/
private void postgreFromItemsClause(final List<_TabularBlock> blockList, final _MultiTableStmtContext context,
final boolean nested) {
final int blockSize = blockList.size();
assert blockSize > 0;
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
_TabularBlock block;
TabularItem tabularItem;
TableMeta> table;
String alias;
_JoinType joinType;
List<_Predicate> predicateList;
SQLWords modifier;
for (int i = 0; i < blockSize; i++) {
block = blockList.get(i);
joinType = block.jointType();
if (i > 0) {
assert joinType != _JoinType.NONE;
sqlBuilder.append(joinType.spaceRender());
} else {
assert joinType == _JoinType.NONE;
}
tabularItem = block.tableItem();
alias = block.alias();
if (tabularItem instanceof TableMeta) {
table = (TableMeta>) tabularItem;
if (block instanceof _ModifierTabularBlock
&& (modifier = ((_ModifierTabularBlock) block).modifier()) != null) {
assert modifier == SQLs.ONLY;
sqlBuilder.append(modifier.spaceRender());
}
sqlBuilder.append(_Constant.SPACE);
this.safeObjectName(table, sqlBuilder);
sqlBuilder.append(_Constant.SPACE_AS_SPACE)
.append(context.safeTableAlias(table, alias));
if (block instanceof _PostgreTableBlock) {
this.postgreTableSampleClause((_PostgreTableBlock) block, context);
}
} else if (tabularItem instanceof DerivedTable) {
if (block instanceof _ModifierTabularBlock
&& (modifier = ((_ModifierTabularBlock) block).modifier()) != null) {
assert modifier == SQLs.LATERAL;
sqlBuilder.append(modifier.spaceRender());
}
if (tabularItem instanceof SubQuery) {
this.handleSubQuery((SubQuery) tabularItem, context);
} else if (tabularItem instanceof SubValues) {
this.handleSubValues((SubValues) tabularItem, context);
} else {
// function
((_SelfDescribed) tabularItem).appendSql(sqlBuilder, context);
}
sqlBuilder.append(_Constant.SPACE_AS_SPACE);
this.identifier(alias, sqlBuilder);
if (block instanceof _AliasDerivedBlock) {
this.derivedColumnAliasClause((_AliasDerivedBlock) block, context);
}
} else if (tabularItem instanceof _NestedItems) {
_PostgreConsultant.assertNestedItems((_NestedItems) tabularItem);
if (_StringUtils.hasText(alias)) {
throw _Exceptions.nestedItemsAliasHasText(alias);
}
sqlBuilder.append(_Constant.SPACE_LEFT_PAREN);
this.postgreFromItemsClause(((_NestedItems) tabularItem).tableBlockList(), context, true);
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
} else if (tabularItem instanceof _Cte) {
_PostgreConsultant.assertPostgreCte((_Cte) tabularItem);
sqlBuilder.append(_Constant.SPACE);
this.identifier(((_Cte) tabularItem).name(), sqlBuilder);
if (_StringUtils.hasText(alias)) {
sqlBuilder.append(_Constant.SPACE_AS_SPACE);
this.identifier(alias, sqlBuilder);
} else if (!"".equals(alias)) {
throw _Exceptions.tableItemAliasNoText(tabularItem);
}
} else if (tabularItem instanceof UndoneFunction) {
final _DoneFuncBlock funcBlock = (_DoneFuncBlock) block;
if ((modifier = funcBlock.modifier()) != null) {
assert modifier == SQLs.LATERAL;
sqlBuilder.append(modifier.spaceRender());
}
// undone function
((_SelfDescribed) tabularItem).appendSql(sqlBuilder, context);
sqlBuilder.append(_Constant.SPACE_AS_SPACE);
this.identifier(alias, sqlBuilder);
sqlBuilder.append(_Constant.SPACE_LEFT_PAREN);
final List<_FunctionField> fieldList = funcBlock.fieldList();
final int fieldSize = fieldList.size();
for (int fieldIndex = 0; fieldIndex < fieldSize; fieldIndex++) {
if (fieldIndex > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
fieldList.get(fieldIndex).appendSql(sqlBuilder, context);
}
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
} else {
throw _Exceptions.dontSupportTableItem(tabularItem, alias, this.dialect);
}
switch (joinType) {
case LEFT_JOIN:
case JOIN:
case RIGHT_JOIN:
case FULL_JOIN:
case STRAIGHT_JOIN: {
predicateList = block.onClauseList();
if (!nested) {
this.onClause(predicateList, context);
}
}
break;
case NONE:
case CROSS_JOIN:
break;
default:
throw _Exceptions.unexpectedEnum(joinType);
}
}//for
}
/**
* @see #postgreFromItemsClause(List, _MultiTableStmtContext, boolean)
*/
private void postgreTableSampleClause(final _PostgreTableBlock block, final _SqlContext context) {
}
/**
* @see #parseValuesInsert(_ValueSyntaxInsertContext, _Insert._ValuesSyntaxInsert)
* @see #parseQueryInsert(_QueryInsertContext, _Insert._QueryInsert)
* @see Postgre INSERT syntax
*/
private void parsePostgreInsert(final _InsertContext context, final _PostgreInsert stmt) {
final TableMeta> insertTable;
insertTable = context.insertTable();
if (stmt instanceof _Insert._OneStmtChildInsert) {
((_Insert._OneStmtChildInsert) stmt).validParentDomain();
}
this.parseWithClause(stmt, context);
final StringBuilder sqlBuilder;
if ((sqlBuilder = context.sqlBuilder()).length() > 0) {
sqlBuilder.append(_Constant.SPACE);
}
// 1. INSERT INTO key words
sqlBuilder.append(_Constant.INSERT)
.append(_Constant.SPACE_INTO_SPACE);
// 2. table name
assert insertTable == stmt.table();
this.safeObjectName(insertTable, sqlBuilder);
// 3. row alias
final String safeTableAlias;
if ((safeTableAlias = context.safeTableAlias()) != null) {
sqlBuilder.append(_Constant.SPACE_AS_SPACE)
.append(safeTableAlias);
}
// 4. append column list
((_InsertContext._ColumnListSpec) context).appendFieldList();
// 5. OVERRIDING { SYSTEM | USER } VALUE clause
final SQLWords overridingModifier;
if ((overridingModifier = stmt.overridingValueWords()) != null) {
sqlBuilder.append(overridingModifier.spaceRender());
}
// due to army manage createTime(updateTime) field,so army don't support DEFAULT VALUES
// 6. VALUES/QUERY clause
if (context instanceof _ValueSyntaxInsertContext) {
((_ValueSyntaxInsertContext) context).appendValueList();
} else {
((_QueryInsertContext) context).appendSubQuery();
}
// 7. ON CONFLICT clause
final _PostgreInsert._ConflictActionClauseResult conflictClause;
if ((conflictClause = stmt.getConflictActionResult()) != null) {
this.insertOnConflictClause(context, conflictClause);
}
// 8. RETURNING clause
if (stmt instanceof _ReturningDml) {
returningClause(context, (_ReturningDml) stmt);
} else if (context instanceof _ValueSyntaxInsertContext) {
((_InsertContext._ReturningIdSpec) context).appendReturnIdIfNeed();
}
}
/**
* @see #parsePostgreInsert(_InsertContext, _PostgreInsert)
* @see Postgre INSERT syntax
*/
private void insertOnConflictClause(final _InsertContext context,
final _PostgreInsert._ConflictActionClauseResult clause) {
final StringBuilder sqlBuilder;
// 1. ON CONFLICT key words
sqlBuilder = context.sqlBuilder()
.append(SPACE_ON_CONFLICT);
final List<_ConflictTargetItem> targetItemList;
targetItemList = clause.conflictTargetItemList();
final String constraintName;
constraintName = clause.constraintName();
final int targetItemSize;
targetItemSize = targetItemList.size();
if (constraintName != null && targetItemSize > 0) {
throw _Exceptions.castCriteriaApi();
}
// 2. below conflict_target clause
if (constraintName != null) {
sqlBuilder.append(SPACE_ON_CONSTRAINT)
.append(_Constant.SPACE);
this.identifier(constraintName, sqlBuilder);
} else if (targetItemSize > 0) {
sqlBuilder.append(_Constant.SPACE_LEFT_PAREN);
for (int i = 0; i < targetItemSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
targetItemList.get(i).appendSql(sqlBuilder, context);
}
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
final List<_Predicate> indexPredicateList;
indexPredicateList = clause.indexPredicateList();
if (indexPredicateList.size() > 0) {
this.dmlWhereClause(indexPredicateList, context);
}
} else if (clause.indexPredicateList().size() > 0) {
throw _Exceptions.castCriteriaApi();
}
//3. below conflict_action clause
if (clause.isDoNothing()) {
if (clause.updateSetClauseList().size() > 0 || clause.updateSetPredicateList().size() > 0) {
throw _Exceptions.castCriteriaApi();
}
sqlBuilder.append(" DO NOTHING");
} else if (clause.updateSetClauseList().size() == 0
|| (constraintName == null && targetItemSize == 0)) { // For ON CONFLICT DO UPDATE, a conflict_target must be provided.
throw _Exceptions.castCriteriaApi();
} else {
this.insertDoUpdateSetClause(context, clause);
}
}
/**
* @see #insertOnConflictClause(_InsertContext, _PostgreInsert._ConflictActionClauseResult)
* @see Postgre INSERT syntax
*/
private void insertDoUpdateSetClause(final _InsertContext context,
final _PostgreInsert._ConflictActionClauseResult clause) {
final List<_ItemPair> updateItemList;
updateItemList = clause.updateSetClauseList();
final int updateItemSize;
updateItemSize = updateItemList.size();
assert updateItemSize > 0;
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
sqlBuilder.append(" DO UPDATE SET");
for (int i = 0; i < updateItemSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
updateItemList.get(i).appendItemPair(sqlBuilder, context);
}
final TableMeta> insertTable = context.insertTable();
final List<_Predicate> updatePredicateList;
updatePredicateList = clause.updateSetPredicateList();
final boolean visibleIsFirstPredicate;
if (updatePredicateList.size() > 0) {
this.dmlWhereClause(updatePredicateList, context);
context.appendConditionPredicate(false);
visibleIsFirstPredicate = false;
} else if (context.hasConditionPredicate()) {
sqlBuilder.append(_Constant.SPACE_WHERE);
context.appendConditionPredicate(true);
visibleIsFirstPredicate = false;
} else {
visibleIsFirstPredicate = true;
}
if (context.visible() != Visible.BOTH && insertTable.containComplexField(_MetaBridge.VISIBLE)) {
if (visibleIsFirstPredicate) {
sqlBuilder.append(_Constant.SPACE_WHERE);
}
if (insertTable instanceof SingleTableMeta) {
this.visiblePredicate((SingleTableMeta>) insertTable, context.safeTableAlias(), context, visibleIsFirstPredicate);
} else {
this.parentVisiblePredicate(context, visibleIsFirstPredicate);
}
}
}
/**
* @see #parseSimpleQuery(_Query, _SimpleQueryContext)
*/
private void postgreLockClause(final _PostgreQuery stmt, final _SimpleQueryContext context) {
final List<_Query._LockBlock> blockList = stmt.lockBlockList();
if (blockList.size() == 0) {
return;
}
final List extends SQLWords> modifierList = stmt.modifierList();
if (modifierList.contains(Postgres.DISTINCT)) {
String m = String.format("%s Currently, lock clause cannot be specified with DISTINCT", this.dialect);
throw new CriteriaException(m);
}
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
List tableAliasList;
int tableAliasSize;
SQLWords waitOption;
for (_Query._LockBlock block : blockList) {
sqlBuilder.append(block.lockStrength().spaceRender());
tableAliasList = block.lockTableAliasList();
tableAliasSize = tableAliasList.size();
if (tableAliasSize > 0) {
sqlBuilder.append(_Constant.SPACE_OF_SPACE);
for (int i = 0; i < tableAliasSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA_SPACE);
}
sqlBuilder.append(context.safeTableAlias(tableAliasList.get(i)));
}
}// if(tableAliasSize >0)
waitOption = block.lockWaitOption();
if (waitOption != null) {
sqlBuilder.append(waitOption.spaceRender());
}
}
}
/*-------------------below static method -------------------*/
/**
* @see #parsePostgreInsert(_InsertContext, _PostgreInsert)
* @see #parseSingleUpdate(_SingleUpdate, _SingleUpdateContext)
* @see #parseSingleDelete(_SingleDelete, _SingleDeleteContext)
*/
private static void returningClause(final _SqlContext context, final _ReturningDml stmt) {
final List extends _SelectItem> selectionList;
selectionList = stmt.returningList();
final int selectionSize;
selectionSize = selectionList.size();
if (selectionSize == 0) {
return;
}
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder()
.append(_Constant.SPACE_RETURNING);
for (int i = 0; i < selectionSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
selectionList.get(i).appendSelectItem(sqlBuilder, context);
}
}
/**
* @see #parseSimpleQuery(_Query, _SimpleQueryContext)
*/
private static void distinctOnExpressionsClause(final _PostgreQuery stmt, final _SimpleQueryContext context) {
final List<_Expression> expList = stmt.distinctOnExpressions();
final int distinctOnExpSize = expList.size();
if (distinctOnExpSize == 0) {
return;
}
final List extends SQLWords> modifierList = stmt.modifierList();
if (modifierList.size() != 1 || modifierList.get(0) != Postgres.DISTINCT) {
throw _Exceptions.castCriteriaApi();
}
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder()
.append(_Constant.SPACE_ON)
.append(_Constant.LEFT_PAREN);
for (int i = 0; i < distinctOnExpSize; i++) {
if (i > 0) {
sqlBuilder.append(_Constant.SPACE_COMMA);
}
expList.get(i).appendSql(sqlBuilder, context);
}
sqlBuilder.append(_Constant.SPACE_RIGHT_PAREN);
}
/**
* @see #parseClauseAfterRightParen(_ParensRowSet, _ParenRowSetContext)
* @see #parseSimpleQuery(_Query, _SimpleQueryContext)
* @see #parseSimpleValues(_ValuesQuery, _ValuesContext)
*/
private static void postgreLimitClause(final _Statement._SQL2008LimitClauseSpec stmt, final _SqlContext context) {
final StringBuilder sqlBuilder;
sqlBuilder = context.sqlBuilder();
final _Expression rowCountExp, offsetExp;
rowCountExp = stmt.rowCountExp();
offsetExp = stmt.offsetExp();
final SQLWords fetchFirstNext;
fetchFirstNext = stmt.fetchFirstOrNext();
// LIMIT clause
if (fetchFirstNext == null && rowCountExp != null) {
sqlBuilder.append(_Constant.SPACE_LIMIT);
rowCountExp.appendSql(sqlBuilder, context);
}
// OFFSET clause
if (offsetExp != null) {
sqlBuilder.append(_Constant.SPACE_OFFSET);
offsetExp.appendSql(sqlBuilder, context);
final SQLWords offsetRow;
if ((offsetRow = stmt.offsetRowModifier()) != null) {
if (offsetRow != SQLs.ROW && offsetRow != SQLs.ROWS) {
throw _Exceptions.castCriteriaApi();
}
sqlBuilder.append(offsetRow.spaceRender());
}
}
// FETCH clause
if (fetchFirstNext != null) {
if (rowCountExp == null) {
throw _Exceptions.castCriteriaApi();
}
final SQLWords fetchRowRows, fetchOnlyWithTies;
fetchRowRows = stmt.fetchRowModifier();
fetchOnlyWithTies = stmt.fetchOnlyOrWithTies();
if (fetchRowRows != SQLs.ROW && fetchRowRows != SQLs.ROWS) {
throw _Exceptions.castCriteriaApi();
} else if (fetchOnlyWithTies == null || stmt.fetchPercentModifier() != null) {
throw _Exceptions.castCriteriaApi();
} else if (fetchOnlyWithTies != SQLs.ONLY && fetchOnlyWithTies != SQLs.WITH_TIES) {
throw errorFetchOnlyOrWithTies(fetchOnlyWithTies);
}
sqlBuilder.append(_Constant.SPACE_FETCH)
.append(fetchFirstNext.spaceRender());
rowCountExp.appendSql(sqlBuilder, context);
sqlBuilder.append(fetchRowRows.spaceRender())
.append(fetchOnlyWithTies.spaceRender());
}
}
private static CriteriaException errorFetchOnlyOrWithTies(@Nullable SQLWords words) {
String m = String.format("Postgre don't support modifier[%s] in FETCH clause.", words);
return new CriteriaException(m);
}
}