Skip to content

Commit d390347

Browse files
kitaisrealsbrannen
authored andcommitted
Support quoted identifiers in SimpleJdbcInsert
See gh-24013
1 parent 070590c commit d390347

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
7777
/** Collection of TableParameterMetaData objects. */
7878
private final List<TableParameterMetaData> tableParameterMetaData = new ArrayList<>();
7979

80+
/** the string used to quote SQL identifiers. */
81+
private String identifierQuoteString = "";
8082

8183
/**
8284
* Constructor used to initialize with provided database meta-data.
@@ -213,6 +215,15 @@ public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQL
213215
logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers': " + ex.getMessage());
214216
}
215217
}
218+
219+
try {
220+
this.identifierQuoteString = databaseMetaData.getIdentifierQuoteString();
221+
}
222+
catch (SQLException ex) {
223+
if (logger.isWarnEnabled()) {
224+
logger.warn("Error retrieving 'DatabaseMetaData.getIdentifierQuoteString': " + ex.getMessage());
225+
}
226+
}
216227
}
217228

218229
@Override
@@ -293,6 +304,14 @@ protected String getDatabaseVersion() {
293304
return this.databaseVersion;
294305
}
295306

307+
/**
308+
* Provide access to identifier quote string.
309+
*/
310+
@Override
311+
public String getIdentifierQuoteString() {
312+
return this.identifierQuoteString;
313+
}
314+
296315
/**
297316
* Method supporting the meta-data processing for a table.
298317
*/

spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ public class TableMetaDataContext {
7979
// Are we using generated key columns
8080
private boolean generatedKeyColumnsUsed = false;
8181

82+
// Are we using escaping for SQL identifiers
83+
private boolean usingEscaping = false;
84+
8285

8386
/**
8487
* Set the name of the table for this context.
@@ -276,13 +279,24 @@ public String createInsertString(String... generatedKeyNames) {
276279
for (String key : generatedKeyNames) {
277280
keys.add(key.toUpperCase());
278281
}
282+
String identifierQuoteString = "";
283+
if (this.metaDataProvider != null && this.usingEscaping) {
284+
identifierQuoteString = this.metaDataProvider.getIdentifierQuoteString();
285+
}
279286
StringBuilder insertStatement = new StringBuilder();
280287
insertStatement.append("INSERT INTO ");
281288
if (getSchemaName() != null) {
289+
insertStatement.append(identifierQuoteString);
282290
insertStatement.append(getSchemaName());
283291
insertStatement.append('.');
292+
insertStatement.append(getTableName());
293+
insertStatement.append(identifierQuoteString);
294+
}
295+
else {
296+
insertStatement.append(identifierQuoteString);
297+
insertStatement.append(getTableName());
298+
insertStatement.append(identifierQuoteString);
284299
}
285-
insertStatement.append(getTableName());
286300
insertStatement.append(" (");
287301
int columnCount = 0;
288302
for (String columnName : getTableColumns()) {
@@ -291,7 +305,9 @@ public String createInsertString(String... generatedKeyNames) {
291305
if (columnCount > 1) {
292306
insertStatement.append(", ");
293307
}
308+
insertStatement.append(identifierQuoteString);
294309
insertStatement.append(columnName);
310+
insertStatement.append(identifierQuoteString);
295311
}
296312
}
297313
insertStatement.append(") VALUES(");
@@ -381,4 +397,11 @@ public boolean isGeneratedKeysColumnNameArraySupported() {
381397
return obtainMetaDataProvider().isGeneratedKeysColumnNameArraySupported();
382398
}
383399

400+
public boolean isUsingEscaping() {
401+
return this.usingEscaping;
402+
}
403+
404+
public void setUsingEscaping(boolean usingEscaping) {
405+
this.usingEscaping = usingEscaping;
406+
}
384407
}

spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,11 @@ void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, @Nulla
139139
*/
140140
List<TableParameterMetaData> getTableParameterMetaData();
141141

142+
/**
143+
* Retrieves the string used to quote SQL identifiers. This method returns a space " " if identifier quoting is not supported.
144+
* {@link DatabaseMetaData#getIdentifierQuoteString()}
145+
* @return database identifier quote string.
146+
*/
147+
String getIdentifierQuoteString();
148+
142149
}

spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,20 @@ public int[] getInsertTypes() {
236236
return this.insertTypes;
237237
}
238238

239+
/**
240+
* Set using using escaping.
241+
*/
242+
public void setUsingEscaping(boolean usingEscaping) {
243+
this.tableMetaDataContext.setUsingEscaping(usingEscaping);
244+
}
245+
246+
/**
247+
* Get using escaping.
248+
*/
249+
public boolean isUsingEscaping() {
250+
return this.tableMetaDataContext.isUsingEscaping();
251+
}
252+
239253

240254
//-------------------------------------------------------------------------
241255
// Methods handling compilation issues

spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/SimpleJdbcInsert.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ public SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData() {
114114
return this;
115115
}
116116

117+
@Override
118+
public SimpleJdbcInsert usingEscaping(boolean usingEscaping) {
119+
setUsingEscaping(usingEscaping);
120+
return this;
121+
}
122+
117123
@Override
118124
public int execute(Map<String, ?> args) {
119125
return doExecute(args);

spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertOperations.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ public interface SimpleJdbcInsertOperations {
8282
*/
8383
SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData();
8484

85+
/**
86+
* Specify should sql identifiers be quoted.
87+
* @param usingEscaping should sql identifiers be quoted
88+
* @return the instance of this SimpleJdbcInsert
89+
*/
90+
SimpleJdbcInsertOperations usingEscaping(boolean usingEscaping);
91+
8592

8693
/**
8794
* Execute the insert using the values passed in.

spring-jdbc/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcInsertTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,37 @@ void exceptionThrownWhileRetrievingColumnNamesFromMetadata() throws Exception {
138138
verify(tableResultSet).close();
139139
}
140140

141+
@Test
142+
public void testSimpleJdbcInsert() {
143+
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("T").usingColumns("F", "S");
144+
jdbcInsert.compile();
145+
String expected = "INSERT INTO T (F, S) VALUES(?, ?)";
146+
String actual = jdbcInsert.getInsertString();
147+
assertThat(actual).isEqualTo(expected);
148+
}
149+
150+
@Test
151+
public void testSimpleJdbcInsertWithEscapingWithSchemaName() throws Exception {
152+
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource).withSchemaName("S").withTableName("T").usingColumns("F", "S").usingEscaping(true);
153+
154+
given(databaseMetaData.getIdentifierQuoteString()).willReturn("`");
155+
156+
jdbcInsert.compile();
157+
String expected = "INSERT INTO `S.T` (`F`, `S`) VALUES(?, ?)";
158+
String actual = jdbcInsert.getInsertString();
159+
assertThat(actual).isEqualTo(expected);
160+
}
161+
162+
@Test
163+
public void testSimpleJdbcInsertWithEscapingWithoutSchemaName() throws Exception {
164+
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("T").usingColumns("F", "S").usingEscaping(true);
165+
166+
given(databaseMetaData.getIdentifierQuoteString()).willReturn("`");
167+
168+
jdbcInsert.compile();
169+
String expected = "INSERT INTO `T` (`F`, `S`) VALUES(?, ?)";
170+
String actual = jdbcInsert.getInsertString();
171+
assertThat(actual).isEqualTo(expected);
172+
}
173+
141174
}

0 commit comments

Comments
 (0)