From 962a0226c98590abc46c0082ebb8ab532b9bbb5a Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Fri, 30 Nov 2012 13:01:15 +0100 Subject: [PATCH] [#1982] Change RenderNameStyle.UPPER, LOWER, AS_IS to quote literals if needed --- .../org/jooq/impl/DefaultRenderContext.java | 75 +++++++++++-------- .../test/java/org/jooq/test/BasicTest.java | 19 +++++ 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index fdfee1add1..a74f931cf3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -38,6 +38,7 @@ package org.jooq.impl; import static java.util.Arrays.asList; import java.util.Stack; +import java.util.regex.Pattern; import org.jooq.Configuration; import org.jooq.QueryPart; @@ -57,23 +58,24 @@ class DefaultRenderContext extends AbstractContext implements Ren /** * Generated UID */ - private static final long serialVersionUID = -8358225526567622252L; + private static final long serialVersionUID = -8358225526567622252L; + private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9_]*"); - private final StringBuilder sql; - private boolean inline; - private boolean renderNamedParams; - private boolean qualify = true; - private int alias; - private CastMode castMode = CastMode.DEFAULT; - private SQLDialect[] castDialects; - private int indent; - private Stack indentLock = new Stack(); - private int printMargin = 80; + private final StringBuilder sql; + private boolean inline; + private boolean renderNamedParams; + private boolean qualify = true; + private int alias; + private CastMode castMode = CastMode.DEFAULT; + private SQLDialect[] castDialects; + private int indent; + private Stack indentLock = new Stack(); + private int printMargin = 80; // [#1632] Cached values from Settings - private RenderKeywordStyle cachedRenderKeywordStyle; - private RenderNameStyle cachedRenderNameStyle; - private boolean cachedRenderFormatted; + private RenderKeywordStyle cachedRenderKeywordStyle; + private RenderNameStyle cachedRenderNameStyle; + private boolean cachedRenderFormatted; DefaultRenderContext(Configuration configuration) { super(configuration); @@ -265,21 +267,43 @@ class DefaultRenderContext extends AbstractContext implements Ren return this; } + // Quoting is needed when explicitly requested... + boolean needsQuote = RenderNameStyle.QUOTED == cachedRenderNameStyle + // ... or when an identifier contains special characters [#1982] + || !IDENTIFIER_PATTERN.matcher(literal).matches(); + if (RenderNameStyle.LOWER == cachedRenderNameStyle) { - sql(literal.toLowerCase()); + literal = literal.toLowerCase(); } else if (RenderNameStyle.UPPER == cachedRenderNameStyle) { - sql(literal.toUpperCase()); + literal = literal.toUpperCase(); } - else if (RenderNameStyle.AS_IS == cachedRenderNameStyle) { + + if (!needsQuote) { sql(literal); } else { switch (configuration.getDialect()) { + + // MySQL supports backticks and double quotes case MYSQL: sql("`").sql(literal.replace("`", "``")).sql("`"); break; + // SQLite is supposed to support all sorts of delimiters, but it + // seems too buggy + case SQLITE: + sql(literal); + break; + + // T-SQL databases use brackets + case ASE: + case SQLSERVER: + case SYBASE: + sql("[").sql(literal.replace("]", "]]")).sql("]"); + break; + + // Most dialects implement the SQL standard, using double quotes case CUBRID: case DB2: case DERBY: @@ -289,23 +313,8 @@ class DefaultRenderContext extends AbstractContext implements Ren case INGRES: case ORACLE: case POSTGRES: - sql('"').sql(literal.replace("\"", "\"\"")).sql('"'); - break; - - // SQLite is supposed to support all sorts of delimiters, but it - // seems too buggy - case SQLITE: - sql(literal); - break; - - case ASE: - case SQLSERVER: - case SYBASE: - sql("[").sql(literal.replace("]", "]]")).sql("]"); - break; - default: - sql(literal); + sql('"').sql(literal.replace("\"", "\"\"")).sql('"'); break; } } diff --git a/jOOQ/src/test/java/org/jooq/test/BasicTest.java b/jOOQ/src/test/java/org/jooq/test/BasicTest.java index 813535cbbe..d7be933199 100644 --- a/jOOQ/src/test/java/org/jooq/test/BasicTest.java +++ b/jOOQ/src/test/java/org/jooq/test/BasicTest.java @@ -2584,6 +2584,25 @@ public class BasicTest { assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref.render(q)); } + @Test + public void testRenderNameStyleWithSpecialCharacters() { + Query q = create.select(val(1).as("Aa \"Bb\" Cc")).from(TABLE1.as("Xx ''Yy''\\ Zz")); + + RenderContext r_refI = r_refI(); + + r_refI.getSettings().setRenderNameStyle(RenderNameStyle.AS_IS); + assertEquals("select 1 \"Aa \"\"Bb\"\" Cc\" from TABLE1 \"Xx ''Yy''\\ Zz\"", r_refI.render(q)); + + r_refI.getSettings().setRenderNameStyle(RenderNameStyle.LOWER); + assertEquals("select 1 \"aa \"\"bb\"\" cc\" from table1 \"xx ''yy''\\ zz\"", r_refI.render(q)); + + r_refI.getSettings().setRenderNameStyle(RenderNameStyle.UPPER); + assertEquals("select 1 \"AA \"\"BB\"\" CC\" from TABLE1 \"XX ''YY''\\ ZZ\"", r_refI.render(q)); + + r_refI.getSettings().setRenderNameStyle(RenderNameStyle.QUOTED); + assertEquals("select 1 \"Aa \"\"Bb\"\" Cc\" from \"TABLE1\" \"Xx ''Yy''\\ Zz\"", r_refI.render(q)); + } + @Test public void testRenderKeywordStyle() { Query q = create.select(val(1)).from(TABLE1).where(FIELD_ID1.equal(2));