Skip to content

Commit c60ff73

Browse files
feat: normalised backtick quotes
Signed-off-by: Andreas Reichel <[email protected]>
1 parent a2487a9 commit c60ff73

File tree

5 files changed

+85
-10
lines changed

5 files changed

+85
-10
lines changed

src/main/java/net/sf/jsqlparser/schema/Column.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public Column(List<String> nameParts, List<String> delimiters) {
5353
}
5454

5555
public Column(String columnName) {
56-
this(null, columnName);
56+
this();
57+
setColumnName(columnName);
5758
}
5859

5960
public ArrayConstructor getArrayConstructor() {
@@ -131,8 +132,56 @@ public String getUnquotedColumnName() {
131132
return MultiPartName.unquote(columnName);
132133
}
133134

134-
public void setColumnName(String string) {
135-
columnName = string;
135+
public void setColumnName(String name) {
136+
// BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair
137+
// of quotes
138+
// however, some people believe that Dots in Names are a good idea, so provide a switch-off
139+
boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null ||
140+
!List
141+
.of("0", "N", "n", "FALSE", "false", "OFF", "off")
142+
.contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER"));
143+
144+
setName(name, splitNamesOnDelimiter);
145+
}
146+
147+
public void setName(String name, boolean splitNamesOnDelimiter) {
148+
if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) {
149+
String[] parts = MultiPartName.unquote(name).split("\\.");
150+
switch (parts.length) {
151+
case 3:
152+
this.table = new Table("\"" + parts[0] + "\".\"" + parts[1] + "\"");
153+
this.columnName = "\"" + parts[2] + "\"";
154+
break;
155+
case 2:
156+
this.table = new Table("\"" + parts[0] + "\"");
157+
this.columnName = "\"" + parts[1] + "\"";
158+
break;
159+
case 1:
160+
this.columnName = "\"" + parts[0] + "\"";
161+
break;
162+
default:
163+
throw new RuntimeException("Invalid column name: " + name);
164+
}
165+
} else if (name.contains(".") && splitNamesOnDelimiter) {
166+
String[] parts = MultiPartName.unquote(name).split("\\.");
167+
switch (parts.length) {
168+
case 3:
169+
this.table = new Table(parts[0] + "." + parts[1]);
170+
this.columnName = parts[2];
171+
break;
172+
case 2:
173+
this.table = new Table(parts[0]);
174+
this.columnName = parts[1];
175+
break;
176+
case 1:
177+
this.columnName = parts[0];
178+
break;
179+
default:
180+
throw new RuntimeException("Invalid column name: " + name);
181+
}
182+
} else {
183+
this.columnName = name;
184+
}
136185
}
137186

138187
public String getTableDelimiter() {

src/main/java/net/sf/jsqlparser/schema/MultiPartName.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,32 @@ static String unquote(String quotedIdentifier) {
2929
}
3030

3131
static boolean isQuoted(String identifier) {
32-
return identifier!=null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find();
32+
return identifier != null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find();
3333
}
3434

3535
String getFullyQualifiedName();
3636

3737
String getUnquotedName();
3838

39+
3940
static String replaceBackticksWithDoubleQuotes(String input) {
4041
if (input == null || input.isEmpty()) {
4142
return input;
4243
}
4344

4445
Matcher matcher = BACKTICK_PATTERN.matcher(input);
4546
StringBuilder sb = new StringBuilder();
47+
int lastEnd = 0;
4648

4749
while (matcher.find()) {
48-
// Replace each backtick-quoted part with double-quoted equivalent
49-
String content = matcher.group(1);
50-
matcher.appendReplacement(sb, "\"" + Matcher.quoteReplacement(content) + "\"");
50+
sb.append(input, lastEnd, matcher.start()); // text before match
51+
sb.append('"').append(matcher.group(1)).append('"'); // replace with double quotes
52+
lastEnd = matcher.end();
5153
}
52-
matcher.appendTail(sb);
5354

55+
sb.append(input.substring(lastEnd)); // append remaining text
5456
return sb.toString();
5557
}
5658

59+
5760
}

src/main/java/net/sf/jsqlparser/schema/Table.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ public Table setTimeTravelStrAfterAlias(String timeTravelStrAfterAlias) {
302302
return this;
303303
}
304304

305+
public void setNameParts(List<String> nameParts) {
306+
this.partItems = nameParts;
307+
}
308+
305309
private void setIndex(int idx, String value) {
306310
int size = partItems.size();
307311
for (int i = 0; i < idx - size + 1; i++) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package net.sf.jsqlparser.schema;
2+
3+
import org.assertj.core.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.*;
7+
8+
class MultiPartNameTest {
9+
10+
@Test
11+
void replaceBackticksWithDoubleQuotes() {
12+
Assertions.assertThat("\"starbake\".\"customers\"").isEqualToIgnoringCase(
13+
MultiPartName.replaceBackticksWithDoubleQuotes("`starbake`.`customers`"));
14+
}
15+
}

src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,10 +1798,14 @@ public void testCount3() throws JSQLParserException {
17981798

17991799
@Test
18001800
public void testMysqlQuote() throws JSQLParserException {
1801-
String statement = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` "
1801+
String sqlStr = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` "
18021802
+ "FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b "
18031803
+ "WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'";
1804-
assertSqlCanBeParsedAndDeparsed(statement);
1804+
1805+
String expected =
1806+
"SELECT \"a\".\"OWNERLASTNAME\", `OWNERFIRSTNAME` FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'";
1807+
1808+
assertStatementCanBeDeparsedAs(CCJSqlParserUtil.parse(sqlStr), expected);
18051809
}
18061810

18071811
@Test

0 commit comments

Comments
 (0)