[#161] Add runtime configuration to pretty print rendered SQL

This commit is contained in:
Lukas Eder 2012-03-02 13:53:57 +00:00
parent 16f1a8555e
commit 5f00b0eb26
35 changed files with 511 additions and 122 deletions

View File

@ -50,6 +50,7 @@ public class jOOQOracleTestInline extends jOOQOracleTest {
protected TestFactory create(Settings settings) {
settings = (settings != null) ? settings : new Settings();
settings.withStatementType(StatementType.STATIC_STATEMENT);
settings.withRenderFormatted(true);
return new TestFactory(getConnection(), settings);
}
}

View File

@ -36,6 +36,7 @@
package org.jooq;
import org.jooq.conf.RenderKeywordStyle;
import org.jooq.conf.Settings;
/**
* The render context is used for rendering {@link QueryPart}'s to SQL. A new
@ -100,6 +101,61 @@ public interface RenderContext extends Context<RenderContext> {
*/
RenderContext sql(QueryPart part);
/**
* Render a new line character (only if {@link Settings#isRenderFormatted()}
* is set to <code>true</code>)
*/
RenderContext formatNewLine();
/**
* Render a new line character (only if {@link Settings#isRenderFormatted()}
* is set to <code>true</code>), or a whitespace separator character
* otherwise
*/
RenderContext formatSeparator();
/**
* Start indenting subsequent SQL by one level (two characters), if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
* <p>
* This is the same as calling {@link #formatIndentStart(int)} with a
* parameter of <code>2</code>
*/
RenderContext formatIndentStart();
/**
* Start indenting subsequent SQL by a number of characters, if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
*/
RenderContext formatIndentStart(int indent);
/**
* Start indenting subsequent SQL at the same level as the current line, if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
*/
RenderContext formatIndentLockStart();
/**
* Stop indenting subsequent SQL by one level (two characters), if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
* <p>
* This is the same as calling {@link #formatIndentEnd(int)} with a
* parameter of <code>2</code>
*/
RenderContext formatIndentEnd();
/**
* Stop indenting subsequent SQL by a number of characters, if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
*/
RenderContext formatIndentEnd(int indent);
/**
* Stop indenting subsequent SQL at the same level as the current line, if
* {@link Settings#isRenderFormatted()} is set to <code>true</code>
*/
RenderContext formatIndentLockEnd();
/**
* Append some (quoted) literal to the context's contained
* {@link StringBuilder}

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -1,8 +1,8 @@
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//
@ -12,6 +12,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@ -21,9 +22,9 @@ import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for Settings complex type.
*
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
*
* <pre>
* &lt;complexType name="Settings">
* &lt;complexContent>
@ -32,6 +33,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;element name="renderMapping" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderMapping" minOccurs="0"/>
* &lt;element name="renderNameStyle" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderNameStyle" minOccurs="0"/>
* &lt;element name="renderKeywordStyle" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderKeywordStyle" minOccurs="0"/>
* &lt;element name="renderFormatted" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
* &lt;element name="statementType" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}StatementType" minOccurs="0"/>
* &lt;element name="executeLogging" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
* &lt;element name="executeListeners" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}ExecuteListeners" minOccurs="0"/>
@ -40,8 +42,8 @@ import javax.xml.bind.annotation.XmlType;
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Settings", propOrder = {
@ -57,6 +59,8 @@ public class Settings
protected RenderNameStyle renderNameStyle = RenderNameStyle.QUOTED;
@XmlElement(defaultValue = "LOWER")
protected RenderKeywordStyle renderKeywordStyle = RenderKeywordStyle.LOWER;
@XmlElement(defaultValue = "false")
protected Boolean renderFormatted = false;
@XmlElement(defaultValue = "PREPARED_STATEMENT")
protected StatementType statementType = StatementType.PREPARED_STATEMENT;
@XmlElement(defaultValue = "true")
@ -67,11 +71,11 @@ public class Settings
/**
* Gets the value of the renderMapping property.
*
*
* @return
* possible object is
* {@link RenderMapping }
*
*
*/
public RenderMapping getRenderMapping() {
return renderMapping;
@ -79,11 +83,11 @@ public class Settings
/**
* Sets the value of the renderMapping property.
*
*
* @param value
* allowed object is
* {@link RenderMapping }
*
*
*/
public void setRenderMapping(RenderMapping value) {
this.renderMapping = value;
@ -91,11 +95,11 @@ public class Settings
/**
* Gets the value of the renderNameStyle property.
*
*
* @return
* possible object is
* {@link RenderNameStyle }
*
*
*/
public RenderNameStyle getRenderNameStyle() {
return renderNameStyle;
@ -103,11 +107,11 @@ public class Settings
/**
* Sets the value of the renderNameStyle property.
*
*
* @param value
* allowed object is
* {@link RenderNameStyle }
*
*
*/
public void setRenderNameStyle(RenderNameStyle value) {
this.renderNameStyle = value;
@ -115,11 +119,11 @@ public class Settings
/**
* Gets the value of the renderKeywordStyle property.
*
*
* @return
* possible object is
* {@link RenderKeywordStyle }
*
*
*/
public RenderKeywordStyle getRenderKeywordStyle() {
return renderKeywordStyle;
@ -127,23 +131,47 @@ public class Settings
/**
* Sets the value of the renderKeywordStyle property.
*
*
* @param value
* allowed object is
* {@link RenderKeywordStyle }
*
*
*/
public void setRenderKeywordStyle(RenderKeywordStyle value) {
this.renderKeywordStyle = value;
}
/**
* Gets the value of the renderFormatted property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isRenderFormatted() {
return renderFormatted;
}
/**
* Sets the value of the renderFormatted property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setRenderFormatted(Boolean value) {
this.renderFormatted = value;
}
/**
* Gets the value of the statementType property.
*
*
* @return
* possible object is
* {@link StatementType }
*
*
*/
public StatementType getStatementType() {
return statementType;
@ -151,11 +179,11 @@ public class Settings
/**
* Sets the value of the statementType property.
*
*
* @param value
* allowed object is
* {@link StatementType }
*
*
*/
public void setStatementType(StatementType value) {
this.statementType = value;
@ -163,11 +191,11 @@ public class Settings
/**
* Gets the value of the executeLogging property.
*
*
* @return
* possible object is
* {@link Boolean }
*
*
*/
public Boolean isExecuteLogging() {
return executeLogging;
@ -175,11 +203,11 @@ public class Settings
/**
* Sets the value of the executeLogging property.
*
*
* @param value
* allowed object is
* {@link Boolean }
*
*
*/
public void setExecuteLogging(Boolean value) {
this.executeLogging = value;
@ -207,6 +235,11 @@ public class Settings
return this;
}
public Settings withRenderFormatted(Boolean value) {
setRenderFormatted(value);
return this;
}
public Settings withStatementType(StatementType value) {
setStatementType(value);
return this;

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.02.29 at 08:45:52 PM MEZ
// Generated on: 2012.03.01 at 10:44:24 PM MEZ
//
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd")

View File

@ -245,7 +245,8 @@ implements
}
if (forUpdate) {
context.keyword(" for update");
context.formatSeparator()
.keyword("for update");
if (!forUpdateOf.isEmpty()) {
context.keyword(" of ");
@ -288,12 +289,14 @@ implements
// MySQL has a non-standard implementation for the "FOR SHARE" clause
case MYSQL:
context.keyword(" lock in share mode");
context.formatSeparator()
.keyword("lock in share mode");
break;
// Postgres is known to implement the "FOR SHARE" clause like this
default:
context.keyword(" for share");
context.formatSeparator()
.keyword("for share");
break;
}
}
@ -304,8 +307,6 @@ implements
*/
private void toSQLReferenceLimitDefault(RenderContext context) {
toSQLReference0(context);
context.sql(" ");
context.sql(getLimit());
}
@ -321,9 +322,12 @@ implements
String subqueryName = "limit_" + Util.hash(enclosed);
String rownumName = "rownum_" + Util.hash(enclosed);
context.keyword("select * from (select ")
context.keyword("select * from (")
.formatIndentStart()
.formatNewLine()
.keyword("select ")
.sql(subqueryName)
.sql(".*, row_number()")
.sql(".*, row_number() ")
.keyword("over (order by ");
if (getOrderBy().isEmpty()) {
@ -344,18 +348,27 @@ implements
context.keyword(") as ")
.sql(rownumName)
.keyword(" from (")
.formatSeparator()
.keyword("from (")
.formatIndentStart()
.formatNewLine()
.sql(enclosed)
.formatIndentEnd()
.formatNewLine()
.keyword(") as ")
.sql(subqueryName)
.formatIndentEnd()
.formatNewLine()
.keyword(") as ")
.sql("outer_")
.sql(subqueryName)
.keyword(" where ")
.formatSeparator()
.keyword("where ")
.sql(rownumName)
.sql(" > ")
.sql(getLimit().getLowerRownum())
.keyword(" and ")
.formatSeparator()
.keyword("and ")
.sql(rownumName)
.sql(" <= ")
.sql(getLimit().getUpperRownum());
@ -373,19 +386,32 @@ implements
String subqueryName = "limit_" + Util.hash(enclosed);
String rownumName = "rownum_" + Util.hash(enclosed);
context.keyword("select * from (select ")
context.keyword("select * from (")
.formatIndentStart()
.formatNewLine()
.keyword("select ")
.sql(subqueryName)
.keyword(".*, rownum as ")
.sql(rownumName)
.keyword(" from (")
.formatSeparator()
.keyword("from (")
.formatIndentStart()
.formatNewLine()
.sql(enclosed)
.formatIndentEnd()
.formatNewLine()
.sql(") ")
.sql(subqueryName)
.keyword(") where ")
.formatIndentEnd()
.formatNewLine()
.keyword(")")
.formatSeparator()
.keyword("where ")
.sql(rownumName)
.sql(" > ")
.sql(getLimit().getLowerRownum())
.keyword(" and ")
.formatSeparator()
.keyword("and ")
.sql(rownumName)
.sql(" <= ")
.sql(getLimit().getUpperRownum());
@ -452,7 +478,9 @@ implements
context.declareTables(true);
if (!context.render(getFrom()).isEmpty()) {
context.keyword(" from ").sql(getFrom());
context.formatSeparator()
.keyword("from ")
.sql(getFrom());
}
context.declareTables(false);
@ -460,13 +488,16 @@ implements
// WHERE clause
// ------------
if (!(getWhere().getWhere() instanceof TrueCondition)) {
context.keyword(" where ").sql(getWhere());
context.formatSeparator()
.keyword("where ")
.sql(getWhere());
}
// CONNECT BY clause
// -----------------
if (!(getConnectBy().getWhere() instanceof TrueCondition)) {
context.keyword(" connect by");
context.formatSeparator()
.keyword("connect by");
if (connectByNoCycle) {
context.keyword(" nocycle");
@ -475,24 +506,32 @@ implements
context.sql(" ").sql(getConnectBy());
if (!(getConnectByStartWith().getWhere() instanceof TrueCondition)) {
context.keyword(" start with ").sql(getConnectByStartWith());
context.formatSeparator()
.keyword("start with ")
.sql(getConnectByStartWith());
}
}
// GROUP BY and HAVING clause
// --------------------------
if (!getGroupBy().isEmpty()) {
context.keyword(" group by ").sql(getGroupBy());
context.formatSeparator()
.keyword("group by ")
.sql(getGroupBy());
}
if (!(getHaving().getWhere() instanceof TrueCondition)) {
context.keyword(" having ").sql(getHaving());
context.formatSeparator()
.keyword("having ")
.sql(getHaving());
}
// ORDER BY clause
// ---------------
if (!getOrderBy().isEmpty()) {
context.keyword(" order by ").sql(getOrderBy());
context.formatSeparator()
.keyword("order by ")
.sql(getOrderBy());
}
}

View File

@ -77,7 +77,9 @@ class ArrayAsSubqueryCondition<T> extends AbstractCondition {
.sql(" ")
.keyword(operator.toSQL())
.sql(" (")
.formatIndentLockStart()
.sql(array(context))
.formatIndentLockEnd()
.sql(")");
}

View File

@ -117,9 +117,16 @@ class CaseConditionStepImpl<T> extends AbstractField<T> implements CaseCondition
@Override
public final void toSQL(RenderContext context) {
context.keyword("case");
context.formatIndentLockStart()
.keyword("case")
.formatIndentLockStart();
int size = conditions.size();
for (int i = 0; i < size; i++) {
if (i > 0) {
context.formatSeparator();
}
for (int i = 0; i < conditions.size(); i++) {
context.keyword(" when ")
.sql(conditions.get(i))
.keyword(" then ")
@ -127,11 +134,22 @@ class CaseConditionStepImpl<T> extends AbstractField<T> implements CaseCondition
}
if (otherwise != null) {
context.keyword(" else ")
context.formatSeparator()
.keyword(" else ")
.sql(otherwise);
}
context.keyword(" end");
context.formatIndentLockEnd();
if (size > 1 || otherwise != null) {
context.formatSeparator();
}
else {
context.sql(" ");
}
context.keyword("end")
.formatIndentLockEnd();
}
@Override

View File

@ -149,13 +149,21 @@ class CaseWhenStepImpl<V, T> extends AbstractField<T> implements CaseWhenStep<V,
@Override
public final void toSQL(RenderContext context) {
context.keyword("case");
context.formatIndentLockStart()
.keyword("case");
int size = compareValues.size();
switch (context.getDialect()) {
// The DERBY dialect doesn't support the simple CASE clause
case DERBY: {
for (int i = 0; i < compareValues.size(); i++) {
context.formatIndentLockStart();
for (int i = 0; i < size; i++) {
if (i > 0) {
context.formatSeparator();
}
context.keyword(" when ");
context.sql(value.equal(compareValues.get(i)));
context.keyword(" then ");
@ -166,9 +174,15 @@ class CaseWhenStepImpl<V, T> extends AbstractField<T> implements CaseWhenStep<V,
}
default: {
context.sql(" ").sql(value);
context.sql(" ")
.sql(value)
.formatIndentLockStart();
for (int i = 0; i < size; i++) {
if (i > 0) {
context.formatSeparator();
}
for (int i = 0; i < compareValues.size(); i++) {
context.keyword(" when ");
context.sql(compareValues.get(i));
context.keyword(" then ");
@ -180,10 +194,22 @@ class CaseWhenStepImpl<V, T> extends AbstractField<T> implements CaseWhenStep<V,
}
if (otherwise != null) {
context.keyword(" else ").sql(otherwise);
context.formatSeparator()
.keyword(" else ")
.sql(otherwise);
}
context.keyword(" end");
context.formatIndentLockEnd();
if (size > 1 || otherwise != null) {
context.formatSeparator();
}
else {
context.sql(" ");
}
context.keyword("end")
.formatIndentLockEnd();
}
@Override

View File

@ -113,19 +113,25 @@ class CombinedCondition extends AbstractCondition {
context.sql(conditions.get(0));
}
else {
context.sql("(");
context.sql("(")
.formatIndentLockStart();
String operatorName = " " + operator.name().toLowerCase() + " ";
String separator = "";
for (Condition condition : conditions) {
for (int i = 0; i < conditions.size(); i++) {
context.keyword(separator);
context.sql(condition);
if (i > 0) {
context.formatNewLine();
}
context.sql(conditions.get(i));
separator = operatorName;
}
context.sql(")");
context.sql(")")
.formatIndentLockEnd();
}
}
}

View File

@ -37,6 +37,8 @@ package org.jooq.impl;
import static java.util.Arrays.asList;
import java.util.Stack;
import org.jooq.Configuration;
import org.jooq.QueryPart;
import org.jooq.QueryPartInternal;
@ -44,6 +46,7 @@ import org.jooq.RenderContext;
import org.jooq.SQLDialect;
import org.jooq.conf.RenderKeywordStyle;
import org.jooq.conf.RenderNameStyle;
import org.jooq.tools.StringUtils;
/**
* @author Lukas Eder
@ -61,6 +64,8 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
private int alias;
private CastMode castMode = CastMode.DEFAULT;
private SQLDialect[] castDialects;
private int indent;
private Stack<Integer> indentLock = new Stack<Integer>();
DefaultRenderContext(Configuration configuration) {
super(configuration);
@ -113,7 +118,13 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
@Override
public final RenderContext sql(String s) {
sql.append(s);
if (s != null && Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
sql.append(s.replaceAll("[\\n\\r]", "$0" + indentation()));
}
else {
sql.append(s);
}
return this;
}
@ -129,6 +140,80 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
return this;
}
@Override
public final RenderContext formatNewLine() {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
sql.append("\n");
sql.append(indentation());
}
return this;
}
private final String indentation() {
return StringUtils.leftPad("", indent, " ");
}
@Override
public final RenderContext formatSeparator() {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
formatNewLine();
}
else {
sql.append(" ");
}
return this;
}
@Override
public final RenderContext formatIndentStart() {
return formatIndentStart(2);
}
@Override
public final RenderContext formatIndentEnd() {
return formatIndentEnd(2);
}
@Override
public final RenderContext formatIndentStart(int i) {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
indent += i;
}
return this;
}
@Override
public final RenderContext formatIndentEnd(int i) {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
indent -= i;
}
return this;
}
@Override
public final RenderContext formatIndentLockStart() {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
indentLock.push(indent);
String[] lines = sql.toString().split("[\\n\\r]");
indent = lines[lines.length - 1].length();
}
return this;
}
@Override
public final RenderContext formatIndentLockEnd() {
if (Boolean.TRUE.equals(getSettings().isRenderFormatted())) {
indent = indentLock.pop();
}
return this;
}
@Override
public final RenderContext literal(String literal) {
// Literal usually originates from NamedQueryPart.getName(). This could

View File

@ -110,8 +110,9 @@ class DeleteQueryImpl<R extends Record> extends AbstractQuery implements DeleteQ
context.sql(getFrom());
if (!(getWhere() instanceof TrueCondition)) {
context.keyword(" where ");
context.sql(getWhere());
context.formatSeparator()
.keyword("where ")
.sql(getWhere());
}
}
}

View File

@ -61,35 +61,66 @@ class FieldMapForInsert extends AbstractQueryPartMap<Field<?>, Field<?>> {
@Override
public final void toSQL(RenderContext context) {
toSQLReferenceKeys(context);
context.keyword(" values ");
context.formatSeparator()
.keyword("values ");
toSQLReferenceValues(context);
}
final void toSQLReferenceKeys(RenderContext context) {
boolean indent = (size() > 1);
context.sql("(");
if (indent) {
context.formatIndentStart();
}
String separator = "";
for (Field<?> field : keySet()) {
context.sql(separator);
context.literal(field.getName());
if (indent) {
context.formatNewLine();
}
context.literal(field.getName());
separator = ", ";
}
if (indent) {
context.formatIndentEnd()
.formatNewLine();
}
context.sql(")");
}
final void toSQLReferenceValues(RenderContext context) {
boolean indent = (size() > 1);
context.sql("(");
if (indent) {
context.formatIndentStart();
}
String separator = "";
for (Field<?> field : values()) {
context.sql(separator);
context.sql(field);
if (indent) {
context.formatNewLine();
}
context.sql(field);
separator = ", ";
}
if (indent) {
context.formatIndentEnd()
.formatNewLine();
}
context.sql(")");
}

View File

@ -62,8 +62,13 @@ class FieldMapForUpdate extends AbstractQueryPartMap<Field<?>, Field<?>> {
String separator = "";
for (Entry<Field<?>, Field<?>> entry : entrySet()) {
context.sql(separator)
.literal(entry.getKey().getName())
context.sql(separator);
if (!"".equals(separator)) {
context.formatNewLine();
}
context.literal(entry.getKey().getName())
.sql(" = ")
.sql(entry.getValue());

View File

@ -89,17 +89,20 @@ class InCondition<T> extends AbstractCondition {
case ORACLE:
case INGRES:
case SQLSERVER: {
context.sql("(");
context.sql("(")
.formatIndentLockStart();
for (int i = 0; i < list.size(); i += IN_LIMIT) {
if (i > 0) {
context.keyword(" or ");
context.keyword(" or ")
.formatSeparator();
}
toSQLSubValues(context, list.subList(i, Math.min(i + IN_LIMIT, list.size())));
}
context.sql(")");
context.sql(")")
.formatIndentLockEnd();
break;
}

View File

@ -161,8 +161,9 @@ class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> implements
// MySQL has a nice syntax for this
case MYSQL: {
toSQLInsert(context);
context.keyword(" on duplicate key update ");
context.sql(updateMap);
context.formatSeparator()
.keyword("on duplicate key update ")
.sql(updateMap);
break;
}
@ -238,7 +239,9 @@ class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> implements
if (!returning.isEmpty()) {
switch (context.getDialect()) {
case POSTGRES:
context.keyword(" returning ").sql(returning);
context.formatSeparator()
.keyword("returning ")
.sql(returning);
break;
default:

View File

@ -76,15 +76,21 @@ class InsertSelectQueryImpl<R extends Record> extends AbstractQuery implements I
@Override
public final void toSQL(RenderContext context) {
context.keyword("insert into ").sql(into).sql(" (");
context.keyword("insert into ")
.sql(into)
.sql(" (");
String separator = "";
for (Field<?> field : fields) {
context.sql(separator).literal(field.getName());
context.sql(separator)
.literal(field.getName());
separator = ", ";
}
context.sql(") ").sql(select);
context.sql(")")
.formatSeparator()
.sql(select);
}
@Override

View File

@ -123,7 +123,7 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
@Override
public final void toSQL(RenderContext context) {
context.sql(lhs)
.sql(" ")
.formatSeparator()
.keyword(translateType(context).toSQL())
.sql(" ")

View File

@ -84,6 +84,7 @@ class Limit extends AbstractQueryPart {
case POSTGRES: // No break
case SQLITE: {
context.castMode(NEVER)
.formatSeparator()
.keyword("limit ")
.sql(numberOfRows)
.keyword(" offset ")
@ -97,6 +98,7 @@ class Limit extends AbstractQueryPart {
// Casts are not supported here...
context.castMode(NEVER)
.formatSeparator()
.keyword("offset ")
.sql(offsetOrZero)
.keyword(" rows fetch next ")
@ -112,6 +114,7 @@ class Limit extends AbstractQueryPart {
// INGRES doesn't allow bind variables in the
// OFFSET m FETCH FIRST n ROWS ONLY clause
context.inline(true)
.formatSeparator()
.keyword("offset ")
.sql(offsetOrZero)
.keyword(" fetch first ")
@ -145,6 +148,7 @@ class Limit extends AbstractQueryPart {
// DB2 doesn't allow bind variables here. Casting is not needed.
context.inline(true)
.formatSeparator()
.keyword("fetch first ")
.sql(numberOfRows)
.keyword(" rows only")
@ -171,6 +175,7 @@ class Limit extends AbstractQueryPart {
// A default implementation is necessary for hashCode() and toString()
default: {
context.castMode(NEVER)
.formatSeparator()
.keyword("limit ")
.sql(numberOfRows)
.keyword(" offset ")

View File

@ -317,8 +317,11 @@ implements
context.keyword("merge into ")
.declareTables(true)
.sql(table)
.keyword(" using ")
.formatSeparator()
.keyword("using ")
.formatIndentLockStart()
.sql(Util.wrapInParentheses(context.render(using)))
.formatIndentLockEnd()
.declareTables(false);
switch (context.getDialect()) {
@ -352,36 +355,44 @@ implements
}
}
context.keyword(" on ")
.sql(Util.wrapInParentheses(context.render(on)));
context.formatSeparator()
.keyword("on ")
.formatIndentLockStart()
.sql(Util.wrapInParentheses(context.render(on)))
.formatIndentLockEnd();
// [#999] WHEN MATCHED clause is optional
if (matchedUpdate != null) {
context.keyword(" when matched then update set ")
context.formatSeparator()
.keyword("when matched then update set ")
.sql(matchedUpdate);
}
// [#998] Oracle MERGE extension: WHEN MATCHED THEN UPDATE .. WHERE
if (matchedWhere != null) {
context.keyword(" where ")
context.formatSeparator()
.keyword("where ")
.sql(matchedWhere);
}
// [#998] Oracle MERGE extension: WHEN MATCHED THEN UPDATE .. DELETE WHERE
if (matchedDeleteWhere != null) {
context.keyword(" delete where ")
context.formatSeparator()
.keyword("delete where ")
.sql(matchedDeleteWhere);
}
// [#999] WHEN NOT MATCHED clause is optional
if (notMatchedInsert != null) {
context.sql(" when not matched then insert ")
context.formatSeparator()
.sql("when not matched then insert ")
.sql(notMatchedInsert);
}
// [#998] Oracle MERGE extension: WHEN NOT MATCHED THEN INSERT .. WHERE
if (notMatchedWhere != null) {
context.keyword(" where ")
context.formatSeparator()
.keyword("where ")
.sql(notMatchedWhere);
}

View File

@ -227,13 +227,16 @@ implements
context.declareTables(true)
.sql(table)
.declareTables(declareTables)
.keyword(" pivot(")
.formatSeparator()
.keyword("pivot(")
.inline(true)
.declareFields(true)
.sql(aggregateFunctions)
.keyword(" for ")
.formatSeparator()
.keyword("for ")
.literal(on.getName())
.keyword(" in (")
.formatSeparator()
.keyword("in (")
.sql(in)
.declareFields(declareFields)
.inline(inline)

View File

@ -82,13 +82,23 @@ class QueryPartList<T extends QueryPart> extends AbstractQueryPart implements Li
else {
String separator = "";
boolean indent = (size() > 1);
if (indent)
context.formatIndentStart();
for (T queryPart : this) {
context.sql(separator);
context.sql(queryPart);
if (indent)
context.formatNewLine();
context.sql(queryPart);
separator = ", ";
}
if (indent)
context.formatIndentEnd();
}
}

View File

@ -90,7 +90,8 @@ class Rollup extends AbstractFunction<Object> {
@Override
public final void toSQL(RenderContext context) {
context.sql(new FieldList(Arrays.asList(getArguments())))
.keyword(" with rollup");
.formatSeparator()
.keyword("with rollup");
}
@Override

View File

@ -68,13 +68,20 @@ class SelectQueryAsExistsCondition extends AbstractCondition {
// If this is already a subquery, proceed
if (context.subquery()) {
context.keyword(operator.toSQL()).sql(" (").sql(query).sql(")");
context.keyword(operator.toSQL())
.sql(" (")
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.sql(")");
}
else {
context.keyword(operator.toSQL())
.sql(" (")
.subquery(true)
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.subquery(false)
.sql(")");
}

View File

@ -89,12 +89,18 @@ class SelectQueryAsField<T> extends AbstractField<T> {
// If this is already a subquery, proceed
if (context.subquery()) {
context.sql("(").sql(query).sql(")");
context.sql("(")
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.sql(")");
}
else {
context.sql("(")
.subquery(true)
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.subquery(false)
.sql(")");
}

View File

@ -75,7 +75,9 @@ class SelectQueryAsSubQueryCondition extends AbstractCondition {
.sql(" ")
.keyword(operator.toSQL())
.sql(" (")
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.sql(")");
}
else {
@ -84,7 +86,9 @@ class SelectQueryAsSubQueryCondition extends AbstractCondition {
.keyword(operator.toSQL())
.sql(" (")
.subquery(true)
.formatIndentLockStart()
.sql(query)
.formatIndentLockEnd()
.subquery(false)
.sql(")");
}

View File

@ -87,9 +87,9 @@ class Union<R extends Record> extends AbstractSelect<R> {
public final void toSQL(RenderContext context) {
for (int i = 0; i < queries.size(); i++) {
if (i != 0) {
context.sql(" ");
context.keyword(operator.toSQL(context.getDialect()));
context.sql(" ");
context.formatSeparator()
.keyword(operator.toSQL(context.getDialect()))
.formatSeparator();
}
wrappingParenthesis(context, "(");
@ -112,7 +112,17 @@ class Union<R extends Record> extends AbstractSelect<R> {
return;
}
if (")".equals(parenthesis)) {
context.formatIndentEnd()
.formatNewLine();
}
context.sql(parenthesis);
if ("(".equals(parenthesis)) {
context.formatIndentStart()
.formatNewLine();
}
}
@Override

View File

@ -127,11 +127,16 @@ class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> implements
.declareTables(true)
.sql(getInto())
.declareTables(false)
.keyword(" set ")
.sql(updateMap);
.formatSeparator()
.keyword("set ")
.formatIndentLockStart()
.sql(updateMap)
.formatIndentLockEnd();
if (!(getWhere() instanceof TrueCondition)) {
context.keyword(" where ").sql(getWhere());
context.formatSeparator()
.keyword("where ")
.sql(getWhere());
}
}

View File

@ -139,26 +139,29 @@ implements
}
}
context.keyword(") over (");
String glue = "";
context.keyword(") over (")
.formatIndentLockStart();
boolean newLine = false;
if (!partitionBy.isEmpty()) {
if (partitionByOne && context.getDialect() == SQLDialect.SYBASE) {
// Ignore partition clause. Sybase does not support this construct
}
else {
context.sql(glue)
.keyword("partition by ")
context.keyword("partition by ")
.sql(partitionBy);
glue = " ";
newLine = true;
}
}
if (!orderBy.isEmpty()) {
context.sql(glue)
.keyword("order by ");
if (newLine) {
context.formatSeparator();
}
context.keyword("order by ");
switch (context.getDialect()) {
// SQL Server and Sybase don't allow for fully qualified fields
@ -179,27 +182,32 @@ implements
}
}
glue = " ";
newLine = true;
}
if (rowsStart != null) {
context.sql(glue);
if (newLine) {
context.formatSeparator();
}
context.keyword("rows ");
if (rowsEnd != null) {
context.keyword("between ");
toSQLRows(context, rowsStart);
context.keyword(" and ");
context.formatSeparator()
.keyword("and ");
toSQLRows(context, rowsEnd);
}
else {
toSQLRows(context, rowsStart);
}
glue = " ";
}
context.sql(")");
context.sql(")")
.formatIndentLockEnd();
}
private final String getFNName(SQLDialect dialect) {

View File

@ -28,8 +28,12 @@
This is set to "QUOTED" by default for backwards-compatibility -->
<element name="renderNameStyle" type="jooq-runtime:RenderNameStyle" minOccurs="0" maxOccurs="1" default="QUOTED"/>
<!-- Whether SQL keywords should be rendered with upper or lower case -->
<element name="renderKeywordStyle" type="jooq-runtime:RenderKeywordStyle" minOccurs="0" maxOccurs="1" default="LOWER"/>
<!-- Whether rendered SQL should be pretty-printed -->
<element name="renderFormatted" type="boolean" minOccurs="0" maxOccurs="1" default="false"/>
<!-- The type of statement that is to be executed -->
<element name="statementType" type="jooq-runtime:StatementType" minOccurs="0" maxOccurs="1" default="PREPARED_STATEMENT"/>