diff --git a/jOOQ-test/src/org/jooq/test/jOOQOracleTestInline.java b/jOOQ-test/src/org/jooq/test/jOOQOracleTestInline.java index b3b56e44dd..625dd1d0dc 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQOracleTestInline.java +++ b/jOOQ-test/src/org/jooq/test/jOOQOracleTestInline.java @@ -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); } } \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/RenderContext.java b/jOOQ/src/main/java/org/jooq/RenderContext.java index abcdcf83ed..1b62ac65c6 100644 --- a/jOOQ/src/main/java/org/jooq/RenderContext.java +++ b/jOOQ/src/main/java/org/jooq/RenderContext.java @@ -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 sql(QueryPart part); + /** + * Render a new line character (only if {@link Settings#isRenderFormatted()} + * is set to true) + */ + RenderContext formatNewLine(); + + /** + * Render a new line character (only if {@link Settings#isRenderFormatted()} + * is set to true), or a whitespace separator character + * otherwise + */ + RenderContext formatSeparator(); + + /** + * Start indenting subsequent SQL by one level (two characters), if + * {@link Settings#isRenderFormatted()} is set to true + *

+ * This is the same as calling {@link #formatIndentStart(int)} with a + * parameter of 2 + */ + RenderContext formatIndentStart(); + + /** + * Start indenting subsequent SQL by a number of characters, if + * {@link Settings#isRenderFormatted()} is set to true + */ + RenderContext formatIndentStart(int indent); + + /** + * Start indenting subsequent SQL at the same level as the current line, if + * {@link Settings#isRenderFormatted()} is set to true + */ + RenderContext formatIndentLockStart(); + + /** + * Stop indenting subsequent SQL by one level (two characters), if + * {@link Settings#isRenderFormatted()} is set to true + *

+ * This is the same as calling {@link #formatIndentEnd(int)} with a + * parameter of 2 + */ + RenderContext formatIndentEnd(); + + /** + * Stop indenting subsequent SQL by a number of characters, if + * {@link Settings#isRenderFormatted()} is set to true + */ + RenderContext formatIndentEnd(int indent); + + /** + * Stop indenting subsequent SQL at the same level as the current line, if + * {@link Settings#isRenderFormatted()} is set to true + */ + RenderContext formatIndentLockEnd(); + /** * Append some (quoted) literal to the context's contained * {@link StringBuilder} diff --git a/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java b/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java index 640b8a234f..90d0499e07 100644 --- a/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java +++ b/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/MappedTable.java b/jOOQ/src/main/java/org/jooq/conf/MappedTable.java index d8d6e29228..332c84532c 100644 --- a/jOOQ/src/main/java/org/jooq/conf/MappedTable.java +++ b/jOOQ/src/main/java/org/jooq/conf/MappedTable.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderKeywordStyle.java b/jOOQ/src/main/java/org/jooq/conf/RenderKeywordStyle.java index 0cc8ff7a33..232db90607 100644 --- a/jOOQ/src/main/java/org/jooq/conf/RenderKeywordStyle.java +++ b/jOOQ/src/main/java/org/jooq/conf/RenderKeywordStyle.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java b/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java index 15af68365c..6fdf7aa7df 100644 --- a/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java +++ b/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderNameStyle.java b/jOOQ/src/main/java/org/jooq/conf/RenderNameStyle.java index f71cad2275..77f240bab5 100644 --- a/jOOQ/src/main/java/org/jooq/conf/RenderNameStyle.java +++ b/jOOQ/src/main/java/org/jooq/conf/RenderNameStyle.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 075353b5c4..adc9850187 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -1,8 +1,8 @@ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs -// See http://java.sun.com/xml/jaxb -// 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 http://java.sun.com/xml/jaxb +// 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; /** *

Java class for Settings complex type. - * + * *

The following schema fragment specifies the expected content contained within this class. - * + * *

  * <complexType name="Settings">
  *   <complexContent>
@@ -32,6 +33,7 @@ import javax.xml.bind.annotation.XmlType;
  *         <element name="renderMapping" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderMapping" minOccurs="0"/>
  *         <element name="renderNameStyle" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderNameStyle" minOccurs="0"/>
  *         <element name="renderKeywordStyle" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}RenderKeywordStyle" minOccurs="0"/>
+ *         <element name="renderFormatted" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
  *         <element name="statementType" type="{http://www.jooq.org/xsd/jooq-runtime-2.1.0.xsd}StatementType" minOccurs="0"/>
  *         <element name="executeLogging" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
  *         <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;
  *   </complexContent>
  * </complexType>
  * 
- * - * + * + * */ @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; diff --git a/jOOQ/src/main/java/org/jooq/conf/StatementType.java b/jOOQ/src/main/java/org/jooq/conf/StatementType.java index d9f970ca1d..14e0281650 100644 --- a/jOOQ/src/main/java/org/jooq/conf/StatementType.java +++ b/jOOQ/src/main/java/org/jooq/conf/StatementType.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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 // diff --git a/jOOQ/src/main/java/org/jooq/conf/package-info.java b/jOOQ/src/main/java/org/jooq/conf/package-info.java index f7a4efffb0..4d6556f1fe 100644 --- a/jOOQ/src/main/java/org/jooq/conf/package-info.java +++ b/jOOQ/src/main/java/org/jooq/conf/package-info.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // 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") diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractSubSelect.java b/jOOQ/src/main/java/org/jooq/impl/AbstractSubSelect.java index b489b631ae..be0a702b7a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractSubSelect.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractSubSelect.java @@ -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()); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayAsSubqueryCondition.java b/jOOQ/src/main/java/org/jooq/impl/ArrayAsSubqueryCondition.java index eb3e5cfe7e..2e01153f83 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ArrayAsSubqueryCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/ArrayAsSubqueryCondition.java @@ -77,7 +77,9 @@ class ArrayAsSubqueryCondition extends AbstractCondition { .sql(" ") .keyword(operator.toSQL()) .sql(" (") + .formatIndentLockStart() .sql(array(context)) + .formatIndentLockEnd() .sql(")"); } diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java index 601acafe41..fa555584c2 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java @@ -117,9 +117,16 @@ class CaseConditionStepImpl extends AbstractField 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 extends AbstractField 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 diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java index 6335528669..7ad3a061f4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java @@ -149,13 +149,21 @@ class CaseWhenStepImpl extends AbstractField implements CaseWhenStep 0) { + context.formatSeparator(); + } + context.keyword(" when "); context.sql(value.equal(compareValues.get(i))); context.keyword(" then "); @@ -166,9 +174,15 @@ class CaseWhenStepImpl extends AbstractField implements CaseWhenStep 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 extends AbstractField implements CaseWhenStep 1 || otherwise != null) { + context.formatSeparator(); + } + else { + context.sql(" "); + } + + context.keyword("end") + .formatIndentLockEnd(); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java b/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java index 00b4019c1d..8a5051e963 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java @@ -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(); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index ce6cbb6d4f..337a2f34fc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -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 implements Ren private int alias; private CastMode castMode = CastMode.DEFAULT; private SQLDialect[] castDialects; + private int indent; + private Stack indentLock = new Stack(); DefaultRenderContext(Configuration configuration) { super(configuration); @@ -113,7 +118,13 @@ class DefaultRenderContext extends AbstractContext 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 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 diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java index 732be40160..2e8790a6a9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java @@ -110,8 +110,9 @@ class DeleteQueryImpl extends AbstractQuery implements DeleteQ context.sql(getFrom()); if (!(getWhere() instanceof TrueCondition)) { - context.keyword(" where "); - context.sql(getWhere()); + context.formatSeparator() + .keyword("where ") + .sql(getWhere()); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java index 1020ad1c23..b2925d7ac9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java @@ -61,35 +61,66 @@ class FieldMapForInsert extends AbstractQueryPartMap, 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(")"); } diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java index f2b0375d66..0221b2d95c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java @@ -62,8 +62,13 @@ class FieldMapForUpdate extends AbstractQueryPartMap, Field> { String separator = ""; for (Entry, 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()); diff --git a/jOOQ/src/main/java/org/jooq/impl/InCondition.java b/jOOQ/src/main/java/org/jooq/impl/InCondition.java index ba4001d194..7c173f37af 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/InCondition.java @@ -89,17 +89,20 @@ class InCondition 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; } diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index 9bc5447711..2b55d0fb65 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -161,8 +161,9 @@ class InsertQueryImpl extends AbstractStoreQuery 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 extends AbstractStoreQuery implements if (!returning.isEmpty()) { switch (context.getDialect()) { case POSTGRES: - context.keyword(" returning ").sql(returning); + context.formatSeparator() + .keyword("returning ") + .sql(returning); break; default: diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java index 7b63d78244..0353c8a1d7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java @@ -76,15 +76,21 @@ class InsertSelectQueryImpl 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 diff --git a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java index 726a171079..174d0315ca 100644 --- a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java @@ -123,7 +123,7 @@ class JoinTable extends AbstractTable implements TableOnStep, TableOnCon @Override public final void toSQL(RenderContext context) { context.sql(lhs) - .sql(" ") + .formatSeparator() .keyword(translateType(context).toSQL()) .sql(" ") diff --git a/jOOQ/src/main/java/org/jooq/impl/Limit.java b/jOOQ/src/main/java/org/jooq/impl/Limit.java index 5814001d69..8b21b77d5f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Limit.java +++ b/jOOQ/src/main/java/org/jooq/impl/Limit.java @@ -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 ") diff --git a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java index 548cfdaef2..da77646b4f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java @@ -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); } diff --git a/jOOQ/src/main/java/org/jooq/impl/Pivot.java b/jOOQ/src/main/java/org/jooq/impl/Pivot.java index 12d24c19dd..c27f7bec54 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Pivot.java +++ b/jOOQ/src/main/java/org/jooq/impl/Pivot.java @@ -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) diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java index 20f3f48d92..17380693b3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java +++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java @@ -82,13 +82,23 @@ class QueryPartList 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(); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Rollup.java b/jOOQ/src/main/java/org/jooq/impl/Rollup.java index e680a142fd..66782ce98d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Rollup.java +++ b/jOOQ/src/main/java/org/jooq/impl/Rollup.java @@ -90,7 +90,8 @@ class Rollup extends AbstractFunction { @Override public final void toSQL(RenderContext context) { context.sql(new FieldList(Arrays.asList(getArguments()))) - .keyword(" with rollup"); + .formatSeparator() + .keyword("with rollup"); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java index f929f4d0a2..658c120b74 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java @@ -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(")"); } diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java index 56a174130a..0579a289e6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java @@ -89,12 +89,18 @@ class SelectQueryAsField extends AbstractField { // 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(")"); } diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java index 67e2f81e62..6e2ba223ae 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java @@ -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(")"); } diff --git a/jOOQ/src/main/java/org/jooq/impl/Union.java b/jOOQ/src/main/java/org/jooq/impl/Union.java index 94e5b6e5ad..b81eb2e7e3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Union.java +++ b/jOOQ/src/main/java/org/jooq/impl/Union.java @@ -87,9 +87,9 @@ class Union extends AbstractSelect { 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 extends AbstractSelect { return; } + if (")".equals(parenthesis)) { + context.formatIndentEnd() + .formatNewLine(); + } + context.sql(parenthesis); + + if ("(".equals(parenthesis)) { + context.formatIndentStart() + .formatNewLine(); + } } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java index 8074065ee3..352126b046 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java @@ -127,11 +127,16 @@ class UpdateQueryImpl extends AbstractStoreQuery 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()); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/WindowFunction.java b/jOOQ/src/main/java/org/jooq/impl/WindowFunction.java index 4b148ed2f4..7908ed1b59 100644 --- a/jOOQ/src/main/java/org/jooq/impl/WindowFunction.java +++ b/jOOQ/src/main/java/org/jooq/impl/WindowFunction.java @@ -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) { diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-2.1.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-2.1.0.xsd index 62e0de5d47..4147bfda11 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-2.1.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-2.1.0.xsd @@ -28,8 +28,12 @@ This is set to "QUOTED" by default for backwards-compatibility --> + + + +