bug修改
This commit is contained in:
@ -143,6 +143,10 @@ Connection conn = DriverManager.getConnection(url);
|
||||
The driver supports the V3 frontend/backend protocols. The V3 protocol was introduced in 7.4 and
|
||||
the driver will by default try to connect using the V3 protocol.
|
||||
|
||||
* **quoteReturningIdentifiers** = boolean
|
||||
|
||||
By default we double quote returning identifiers. Some ORM's alraedy allows quote them. Switch allows them to turn this off.
|
||||
|
||||
* **loggerLevel** = String
|
||||
|
||||
Logger level of the driver. Allowed values: <code>OFF</code>, <code>DEBUG</code> or <code>TRACE</code>.
|
||||
|
@ -61,6 +61,17 @@ public enum PGProperty {
|
||||
"Force use of a particular protocol version when connecting, currently only version 3 is supported.",
|
||||
false, "3"),
|
||||
|
||||
/**
|
||||
* Quote returning columns.
|
||||
* There are some ORM's that quote everything, including returning columns
|
||||
* If we quote them, then we end up sending ""colname"" to the backend
|
||||
* which will not be found
|
||||
*/
|
||||
QUOTE_RETURNING_IDENTIFIERS("quoteReturningIdentifiers",
|
||||
"true",
|
||||
"Quote identifiers provided in returning array",
|
||||
false),
|
||||
|
||||
/**
|
||||
* <p>Logger level of the driver. Allowed values: {@code OFF}, {@code DEBUG} or {@code TRACE}.</p>
|
||||
*
|
||||
|
@ -7,6 +7,8 @@ package org.postgresql.core;
|
||||
|
||||
import org.postgresql.util.CanEstimateSize;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Stores information on the parsed JDBC query. It is used to cut parsing overhead when executing
|
||||
* the same query through {@link java.sql.Connection#prepareStatement(String)}.
|
||||
@ -20,7 +22,8 @@ public class CachedQuery implements CanEstimateSize {
|
||||
public final boolean isFunction;
|
||||
public final boolean isACompatibilityFunction;
|
||||
private int executeCount;
|
||||
|
||||
// record queries after rewrite
|
||||
private final ArrayList<Query> rewriteQueries = new ArrayList<>();
|
||||
public CachedQuery(Object key, Query query, boolean isFunction, boolean isACompatibilityFunction) {
|
||||
assert key instanceof String || key instanceof CanEstimateSize
|
||||
: "CachedQuery.key should either be String or implement CanEstimateSize."
|
||||
@ -66,6 +69,42 @@ public class CachedQuery implements CanEstimateSize {
|
||||
+ 100L /* entry in hash map, CachedQuery wrapper, etc */;
|
||||
}
|
||||
|
||||
/**
|
||||
* add rewrite query to list
|
||||
*
|
||||
* @param query the query to add
|
||||
*/
|
||||
public void addRewriteQueries(Query query) {
|
||||
rewriteQueries.add(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* get rewrite queries list
|
||||
*
|
||||
* @return rewrite queries list
|
||||
*/
|
||||
public ArrayList<Query> getRewriteQueries() {
|
||||
return rewriteQueries;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if rewrite queries list empty
|
||||
*
|
||||
* @return check result
|
||||
*/
|
||||
public boolean isRewriteQueriesEmpty() {
|
||||
return rewriteQueries.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* clear rewrite queries
|
||||
*/
|
||||
public void clearRewriteQueries() {
|
||||
if (rewriteQueries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
rewriteQueries.clear();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CachedQuery{"
|
||||
|
@ -65,7 +65,8 @@ class CachedQueryCreateAction implements LruCache.CreateAction<Object, CachedQue
|
||||
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql(parsedSql,
|
||||
queryExecutor.getStandardConformingStrings(), isParameterized, splitStatements,
|
||||
queryExecutor.isReWriteBatchedInsertsEnabled(), returningColumns);
|
||||
queryExecutor.isReWriteBatchedInsertsEnabled(), queryExecutor.getQuoteReturningIdentifiers(),
|
||||
returningColumns);
|
||||
|
||||
Query query = queryExecutor.wrap(queries);
|
||||
return new CachedQuery(key, query, isFunction, isACompatibilityFunction);
|
||||
|
@ -51,6 +51,7 @@ public class Parser {
|
||||
* @param withParameters whether to replace ?, ? with $1, $2, etc
|
||||
* @param splitStatements whether to split statements by semicolon
|
||||
* @param isBatchedReWriteConfigured whether re-write optimization is enabled
|
||||
* @param isQuotedReturningIdentifiers whether to quote identifiers returned using returning clause
|
||||
* @param returningColumnNames for simple insert, update, delete add returning with given column names
|
||||
* @return list of native queries
|
||||
* @throws SQLException if unable to add returning clause (invalid column names)
|
||||
@ -58,6 +59,7 @@ public class Parser {
|
||||
public static List<NativeQuery> parseJdbcSql(String query, boolean standardConformingStrings,
|
||||
boolean withParameters, boolean splitStatements,
|
||||
boolean isBatchedReWriteConfigured,
|
||||
boolean isQuotedReturningIdentifiers,
|
||||
String... returningColumnNames) throws SQLException {
|
||||
int numOfOverSymble = 0;
|
||||
if(startWithComment(query)) {
|
||||
@ -151,8 +153,8 @@ public class Parser {
|
||||
}
|
||||
fragmentStart = i + 1;
|
||||
if (nativeSql.length() > 0) {
|
||||
if (addReturning(
|
||||
nativeSql, currentCommandType, returningColumnNames, isReturningPresent)) {
|
||||
if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent,
|
||||
isQuotedReturningIdentifiers)) {
|
||||
isReturningPresent = true;
|
||||
}
|
||||
|
||||
@ -256,7 +258,8 @@ public class Parser {
|
||||
}
|
||||
fragmentStart = i + 1;
|
||||
if (nativeSql.length() > 0) {
|
||||
if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent)) {
|
||||
if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent,
|
||||
isQuotedReturningIdentifiers)) {
|
||||
isReturningPresent = true;
|
||||
}
|
||||
|
||||
@ -416,7 +419,8 @@ public class Parser {
|
||||
return nativeQueries != null ? nativeQueries : Collections.<NativeQuery>emptyList();
|
||||
}
|
||||
|
||||
if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent)) {
|
||||
if (addReturning(nativeSql, currentCommandType, returningColumnNames, isReturningPresent,
|
||||
isQuotedReturningIdentifiers)) {
|
||||
isReturningPresent = true;
|
||||
}
|
||||
|
||||
@ -526,7 +530,8 @@ public class Parser {
|
||||
}
|
||||
|
||||
private static boolean addReturning(StringBuilder nativeSql, SqlCommandType currentCommandType,
|
||||
String[] returningColumnNames, boolean isReturningPresent) throws SQLException {
|
||||
String[] returningColumnNames, boolean isReturningPresent, boolean isQuotedReturningIdentifiers)
|
||||
throws SQLException {
|
||||
if (isReturningPresent || returningColumnNames.length == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -547,7 +552,11 @@ public class Parser {
|
||||
if (col > 0) {
|
||||
nativeSql.append(", ");
|
||||
}
|
||||
if (isQuotedReturningIdentifiers) {
|
||||
Utils.escapeIdentifier(nativeSql, columnName);
|
||||
} else {
|
||||
nativeSql.append(columnName);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -670,6 +679,7 @@ public class Parser {
|
||||
case "PROCEDURE":
|
||||
case "FUNCTION":
|
||||
case "DECLARE":
|
||||
case "TRIGGER":
|
||||
return true;
|
||||
case "CREATE":
|
||||
if (i == 0) {
|
||||
@ -897,6 +907,7 @@ public class Parser {
|
||||
&& (query[offset + 8] | 32) == 'g';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse string to check presence of SELECT keyword regardless of case.
|
||||
*
|
||||
|
@ -444,6 +444,12 @@ public interface QueryExecutor extends TypeTransferModeRegistry {
|
||||
*/
|
||||
boolean getStandardConformingStrings();
|
||||
|
||||
/**
|
||||
* get quote identifier
|
||||
*
|
||||
* @return true if we are going to quote identifier provided in the returning array default is true
|
||||
*/
|
||||
boolean getQuoteReturningIdentifiers();
|
||||
/**
|
||||
* Returns backend timezone in java format.
|
||||
* @return backend timezone in java format.
|
||||
|
@ -41,6 +41,7 @@ public abstract class QueryExecutorBase implements QueryExecutor {
|
||||
private TransactionState transactionState;
|
||||
private final boolean reWriteBatchedInserts;
|
||||
private final boolean columnSanitiserDisabled;
|
||||
private final boolean isQuotedReturningIdentifiers;
|
||||
private final PreferQueryMode preferQueryMode;
|
||||
private AutoSave autoSave;
|
||||
private boolean flushCacheOnDeallocate = true;
|
||||
@ -64,6 +65,7 @@ public abstract class QueryExecutorBase implements QueryExecutor {
|
||||
this.cancelSignalTimeout = cancelSignalTimeout;
|
||||
this.reWriteBatchedInserts = PGProperty.REWRITE_BATCHED_INSERTS.getBoolean(info);
|
||||
this.columnSanitiserDisabled = PGProperty.DISABLE_COLUMN_SANITISER.getBoolean(info);
|
||||
this.isQuotedReturningIdentifiers = PGProperty.QUOTE_RETURNING_IDENTIFIERS.getBoolean(info);
|
||||
String preferMode = PGProperty.PREFER_QUERY_MODE.get(info);
|
||||
this.preferQueryMode = PreferQueryMode.of(preferMode);
|
||||
this.autoSave = AutoSave.of(PGProperty.AUTOSAVE.get(info));
|
||||
@ -78,6 +80,12 @@ public abstract class QueryExecutorBase implements QueryExecutor {
|
||||
@Override
|
||||
public void evict(CachedQuery cachedQuery) throws SQLException {
|
||||
cachedQuery.query.close();
|
||||
if (!cachedQuery.isRewriteQueriesEmpty()) {
|
||||
for (Query query : cachedQuery.getRewriteQueries()) {
|
||||
query.close();
|
||||
}
|
||||
cachedQuery.clearRewriteQueries();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -261,6 +269,11 @@ public abstract class QueryExecutorBase implements QueryExecutor {
|
||||
return standardConformingStrings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getQuoteReturningIdentifiers() {
|
||||
return isQuotedReturningIdentifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized TransactionState getTransactionState() {
|
||||
return transactionState;
|
||||
|
@ -5,10 +5,10 @@
|
||||
|
||||
package org.postgresql.core.v3;
|
||||
|
||||
import org.postgresql.core.CachedQuery;
|
||||
import org.postgresql.core.NativeQuery;
|
||||
import org.postgresql.core.ParameterList;
|
||||
|
||||
|
||||
/**
|
||||
* Purpose of this object is to support batched query re write behaviour. Responsibility for
|
||||
* tracking the batch size and implement the clean up of the query fragments after the batch execute
|
||||
@ -27,6 +27,8 @@ public class BatchedQuery extends SimpleQuery {
|
||||
private final int batchSize;
|
||||
private BatchedQuery[] blocks;
|
||||
|
||||
// record the origin query of the rewrite query
|
||||
private CachedQuery originalPrepareQuery;
|
||||
public BatchedQuery(NativeQuery query, TypeTransferModeRegistry transferModeRegistry,
|
||||
int valuesBraceOpenPosition,
|
||||
int valuesBraceClosePosition, boolean sanitiserDisabled) {
|
||||
@ -85,6 +87,24 @@ public class BatchedQuery extends SimpleQuery {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* get original prepareQuery
|
||||
*
|
||||
* @return the originalPrepareQuery
|
||||
*/
|
||||
public CachedQuery getOriginalPrepareQuery() {
|
||||
return originalPrepareQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* set original prepareQuery
|
||||
*
|
||||
* @param originalPrepareQuery the originalPrepareQuery to be set
|
||||
*/
|
||||
public void setOriginalPrepareQuery(CachedQuery originalPrepareQuery) {
|
||||
this.originalPrepareQuery = originalPrepareQuery;
|
||||
}
|
||||
|
||||
private String buildNativeSql(ParameterList params) {
|
||||
String buildSql = null;
|
||||
// dynamically build sql with parameters for batches
|
||||
|
@ -10,6 +10,7 @@ import org.postgresql.PGProperty;
|
||||
import org.postgresql.copy.CopyIn;
|
||||
import org.postgresql.copy.CopyOperation;
|
||||
import org.postgresql.copy.CopyOut;
|
||||
import org.postgresql.core.CachedQuery;
|
||||
import org.postgresql.core.CommandCompleteParser;
|
||||
import org.postgresql.core.Encoding;
|
||||
import org.postgresql.core.EncodingPredictor;
|
||||
@ -283,7 +284,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
|
||||
public Query createSimpleQuery(String sql) throws SQLException {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql(sql,
|
||||
getStandardConformingStrings(), false, true,
|
||||
isReWriteBatchedInsertsEnabled());
|
||||
isReWriteBatchedInsertsEnabled(), getQuoteReturningIdentifiers());
|
||||
return wrap(queries);
|
||||
}
|
||||
|
||||
@ -1553,6 +1554,17 @@ public class QueryExecutorImpl extends QueryExecutorBase {
|
||||
pendingDescribePortalQueue.add(sync);
|
||||
}
|
||||
|
||||
private void checkAndUpdateRewriteQueries(SimpleQuery query) {
|
||||
if (!(query instanceof BatchedQuery)) {
|
||||
return;
|
||||
}
|
||||
BatchedQuery batchedQuery = (BatchedQuery) query;
|
||||
CachedQuery originalPrepareQuery = batchedQuery.getOriginalPrepareQuery();
|
||||
if (originalPrepareQuery == null) {
|
||||
return;
|
||||
}
|
||||
originalPrepareQuery.addRewriteQueries(batchedQuery);
|
||||
}
|
||||
private void sendParse(SimpleQuery query, SimpleParameterList params, boolean oneShot)
|
||||
throws IOException {
|
||||
// Already parsed, or we have a Parse pending and the types are right?
|
||||
@ -1582,6 +1594,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
|
||||
query.setStatementName(statementName, deallocateEpoch, getClientEncoding());
|
||||
query.setPrepareTypes(typeOIDs);
|
||||
registerParsedQuery(query, statementName);
|
||||
checkAndUpdateRewriteQueries(query);
|
||||
}
|
||||
|
||||
byte[] encodedStatementName = query.getEncodedStatementName();
|
||||
|
@ -321,6 +321,22 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return quoteReturningIdentifiers
|
||||
* @see PGProperty#QUOTE_RETURNING_IDENTIFIERS
|
||||
*/
|
||||
public boolean getQuoteReturningIdentifiers() {
|
||||
return PGProperty.QUOTE_RETURNING_IDENTIFIERS.getBoolean(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isQuotedIdentifiers indicate whether to quote identifiers
|
||||
* @see PGProperty#QUOTE_RETURNING_IDENTIFIERS
|
||||
*/
|
||||
public void setQuoteReturningIdentifiers(boolean isQuotedIdentifiers) {
|
||||
PGProperty.QUOTE_RETURNING_IDENTIFIERS.set(properties, isQuotedIdentifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return receive buffer size
|
||||
* @see PGProperty#RECEIVE_BUFFER_SIZE
|
||||
|
@ -243,7 +243,7 @@ public class ClientLogic {
|
||||
//Replace the query syntax from jdbc syntax with ? for bind parameters to $1 $2 ... $n
|
||||
List<NativeQuery> queries;
|
||||
try {
|
||||
queries = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
queries = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
} catch (SQLException e) {
|
||||
throw new ClientLogicException(ERROR_PARSER_FAILURE, ERROR_TEXT_PARSER_FAILURE, true);
|
||||
}
|
||||
|
@ -1725,6 +1725,7 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
|
||||
}
|
||||
// Find appropriate batch for block count.
|
||||
BatchedQuery bq = originalQuery.deriveForMultiBatch(valueBlock);
|
||||
bq.setOriginalPrepareQuery(preparedQuery);
|
||||
ParameterList newPl = bq.createParameterList();
|
||||
for (int j = 0; j < valueBlock; j++) {
|
||||
ParameterList pl = batchParameters.get(offset++);
|
||||
|
@ -155,7 +155,7 @@ public class ParserTest {
|
||||
"insert test(id, name) select 1, 'value' as RETURNING from test2";
|
||||
List<NativeQuery> qry =
|
||||
Parser.parseJdbcSql(
|
||||
query, true, true, true, true);
|
||||
query, true, true, true, true, true);
|
||||
boolean returningKeywordPresent = qry.get(0).command.isReturningKeywordPresent();
|
||||
Assert.assertFalse("Query does not have returning clause " + query, returningKeywordPresent);
|
||||
}
|
||||
@ -166,7 +166,7 @@ public class ParserTest {
|
||||
"insert test(id, name) select 1, 'value' from test2 RETURNING id";
|
||||
List<NativeQuery> qry =
|
||||
Parser.parseJdbcSql(
|
||||
query, true, true, true, true);
|
||||
query, true, true, true, true, true);
|
||||
boolean returningKeywordPresent = qry.get(0).command.isReturningKeywordPresent();
|
||||
Assert.assertTrue("Query has a returning clause " + query, returningKeywordPresent);
|
||||
}
|
||||
@ -177,7 +177,7 @@ public class ParserTest {
|
||||
"with x as (insert into mytab(x) values(1) returning x) insert test(id, name) select 1, 'value' from test2";
|
||||
List<NativeQuery> qry =
|
||||
Parser.parseJdbcSql(
|
||||
query, true, true, true, true);
|
||||
query, true, true, true, true, true);
|
||||
boolean returningKeywordPresent = qry.get(0).command.isReturningKeywordPresent();
|
||||
Assert.assertFalse("There's no top-level <<returning>> clause " + query, returningKeywordPresent);
|
||||
}
|
||||
@ -185,7 +185,7 @@ public class ParserTest {
|
||||
@Test
|
||||
public void insertBatchedReWriteOnConflict() throws SQLException {
|
||||
String query = "insert into test(id, name) values (:id,:name) ON CONFLICT (id) DO NOTHING";
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
SqlCommand command = qry.get(0).getCommand();
|
||||
Assert.assertEquals(34, command.getBatchRewriteValuesBraceOpenPosition());
|
||||
Assert.assertEquals(44, command.getBatchRewriteValuesBraceClosePosition());
|
||||
@ -194,7 +194,7 @@ public class ParserTest {
|
||||
@Test
|
||||
public void insertBatchedReWriteOnConflictUpdateBind() throws SQLException {
|
||||
String query = "insert into test(id, name) values (?,?) ON CONFLICT (id) UPDATE SET name=?";
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
SqlCommand command = qry.get(0).getCommand();
|
||||
Assert.assertFalse("update set name=? is NOT compatible with insert rewrite", command.isBatchedReWriteCompatible());
|
||||
}
|
||||
@ -202,7 +202,7 @@ public class ParserTest {
|
||||
@Test
|
||||
public void insertBatchedReWriteOnConflictUpdateConstant() throws SQLException {
|
||||
String query = "insert into test(id, name) values (?,?) ON CONFLICT (id) UPDATE SET name='default'";
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
SqlCommand command = qry.get(0).getCommand();
|
||||
Assert.assertTrue("update set name='default' is compatible with insert rewrite", command.isBatchedReWriteCompatible());
|
||||
}
|
||||
@ -211,7 +211,7 @@ public class ParserTest {
|
||||
public void insertMultiInsert() throws SQLException {
|
||||
String query =
|
||||
"insert into test(id, name) values (:id,:name),(:id,:name) ON CONFLICT (id) DO NOTHING";
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
SqlCommand command = qry.get(0).getCommand();
|
||||
Assert.assertEquals(34, command.getBatchRewriteValuesBraceOpenPosition());
|
||||
Assert.assertEquals(56, command.getBatchRewriteValuesBraceClosePosition());
|
||||
@ -241,7 +241,7 @@ public class ParserTest {
|
||||
for (String mySql: sqlTests) {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql(mySql,
|
||||
false,false,
|
||||
true, false, new String[0]);
|
||||
true, false, true, new String[0]);
|
||||
assertEquals(1, queries.size());
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class ReturningParserTest {
|
||||
String query =
|
||||
"insert into\"prep\"(a, " + prefix + columnName + suffix + ")values(1,2)" + prefix
|
||||
+ returning + suffix;
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true);
|
||||
List<NativeQuery> qry = Parser.parseJdbcSql(query, true, true, true, true, true);
|
||||
boolean returningKeywordPresent = qry.get(0).command.isReturningKeywordPresent();
|
||||
|
||||
boolean expectedReturning = this.returning.equalsIgnoreCase("returning")
|
||||
|
@ -387,6 +387,7 @@ public class TestUtil {
|
||||
props.put(PGProperty.PREFER_QUERY_MODE.getName(), value);
|
||||
}
|
||||
}
|
||||
PGProperty.QUOTE_RETURNING_IDENTIFIERS.set(props, false);
|
||||
// Enable Base4 tests to override host,port,database
|
||||
String hostport = props.getProperty(SERVER_HOST_PORT_PROP, getServer() + ":" + getPort());
|
||||
String database = props.getProperty(DATABASE_PROP, getDatabase());
|
||||
|
@ -95,16 +95,16 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testHasReturning() throws SQLException {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql("insert into foo (a,b,c) values (?,?,?) RetuRning a", true, true, false,
|
||||
true);
|
||||
true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertTrue("The parser should find the word returning", query.command.isReturningKeywordPresent());
|
||||
|
||||
queries = Parser.parseJdbcSql("insert into foo (a,b,c) values (?,?,?)", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("insert into foo (a,b,c) values (?,?,?)", true, true, false, true, true);
|
||||
query = queries.get(0);
|
||||
assertFalse("The parser should not find the word returning", query.command.isReturningKeywordPresent());
|
||||
|
||||
queries = Parser.parseJdbcSql("insert into foo (a,b,c) values ('returning',?,?)", true, true, false,
|
||||
true);
|
||||
true, true);
|
||||
query = queries.get(0);
|
||||
assertFalse("The parser should not find the word returning as it is in quotes ", query.command.isReturningKeywordPresent());
|
||||
}
|
||||
@ -112,7 +112,7 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testSelect() throws SQLException {
|
||||
List<NativeQuery> queries;
|
||||
queries = Parser.parseJdbcSql("select 1 as returning from (update table)", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("select 1 as returning from (update table)", true, true, false, true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("This is a select ", SqlCommandType.SELECT, query.command.getType());
|
||||
assertTrue("Returning is OK here as it is not an insert command ", query.command.isReturningKeywordPresent());
|
||||
@ -121,7 +121,7 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testDelete() throws SQLException {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql("DeLeTe from foo where a=1", true, true, false,
|
||||
true);
|
||||
true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("This is a delete command", SqlCommandType.DELETE, query.command.getType());
|
||||
}
|
||||
@ -130,7 +130,7 @@ public class CompositeQueryParseTest {
|
||||
public void testMultiQueryWithBind() throws SQLException {
|
||||
// braces around (42) are required to puzzle the parser
|
||||
String sql = "INSERT INTO inttable(a) VALUES (?);SELECT (42)";
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql(sql, true, true, true,true);
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql(sql, true, true, true,true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("query(0) of " + sql,
|
||||
"INSERT: INSERT INTO inttable(a) VALUES ($1)",
|
||||
@ -143,7 +143,7 @@ public class CompositeQueryParseTest {
|
||||
|
||||
@Test
|
||||
public void testMove() throws SQLException {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql("MoVe NEXT FROM FOO", true, true, false, true);
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql("MoVe NEXT FROM FOO", true, true, false, true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("This is a move command", SqlCommandType.MOVE, query.command.getType());
|
||||
}
|
||||
@ -152,7 +152,7 @@ public class CompositeQueryParseTest {
|
||||
public void testUpdate() throws SQLException {
|
||||
List<NativeQuery> queries;
|
||||
NativeQuery query;
|
||||
queries = Parser.parseJdbcSql("update foo set (a=?,b=?,c=?)", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("update foo set (a=?,b=?,c=?)", true, true, false, true, true);
|
||||
query = queries.get(0);
|
||||
assertEquals("This is an UPDATE command", SqlCommandType.UPDATE, query.command.getType());
|
||||
}
|
||||
@ -160,11 +160,11 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testInsert() throws SQLException {
|
||||
List<NativeQuery> queries = Parser.parseJdbcSql("InSeRt into foo (a,b,c) values (?,?,?) returning a", true, true, false,
|
||||
true);
|
||||
true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("This is an INSERT command", SqlCommandType.INSERT, query.command.getType());
|
||||
|
||||
queries = Parser.parseJdbcSql("select 1 as insert", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("select 1 as insert", true, true, false, true, true);
|
||||
query = queries.get(0);
|
||||
assertEquals("This is a SELECT command", SqlCommandType.SELECT, query.command.getType());
|
||||
}
|
||||
@ -172,7 +172,7 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testWithSelect() throws SQLException {
|
||||
List<NativeQuery> queries;
|
||||
queries = Parser.parseJdbcSql("with update as (update foo set (a=?,b=?,c=?)) select * from update", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("with update as (update foo set (a=?,b=?,c=?)) select * from update", true, true, false, true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("with ... () select", SqlCommandType.SELECT, query.command.getType());
|
||||
}
|
||||
@ -180,7 +180,7 @@ public class CompositeQueryParseTest {
|
||||
@Test
|
||||
public void testWithInsert() throws SQLException {
|
||||
List<NativeQuery> queries;
|
||||
queries = Parser.parseJdbcSql("with update as (update foo set (a=?,b=?,c=?)) insert into table(select) values(1)", true, true, false, true);
|
||||
queries = Parser.parseJdbcSql("with update as (update foo set (a=?,b=?,c=?)) insert into table(select) values(1)", true, true, false, true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals("with ... () insert", SqlCommandType.INSERT, query.command.getType());
|
||||
}
|
||||
@ -201,7 +201,7 @@ public class CompositeQueryParseTest {
|
||||
boolean splitStatements) {
|
||||
try {
|
||||
return toString(
|
||||
Parser.parseJdbcSql(query, standardConformingStrings, withParameters, splitStatements, false));
|
||||
Parser.parseJdbcSql(query, standardConformingStrings, withParameters, splitStatements, false, true));
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException("Parser.parseJdbcSql: " + e.getMessage(), e);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public class SqlCommandParseTest {
|
||||
@Test
|
||||
public void run() throws SQLException {
|
||||
List<NativeQuery> queries;
|
||||
queries = Parser.parseJdbcSql(sql, true, true, false, true);
|
||||
queries = Parser.parseJdbcSql(sql, true, true, false, true, true);
|
||||
NativeQuery query = queries.get(0);
|
||||
assertEquals(sql, type, query.command.getType());
|
||||
}
|
||||
|
@ -11,10 +11,7 @@ import org.postgresql.util.ExecuteUtil;
|
||||
import org.postgresql.util.RsParser;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.LinkedList;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
@ -63,6 +60,60 @@ public class SelectFunctionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerQuery() throws Exception {
|
||||
String sqlTable = "create table t_tinyint0006 (" + "id int primary key auto_increment,"
|
||||
+ "my_data tinyint" + ");";
|
||||
String sqlTrigger = "create trigger trigger_tinyint0006 before insert on t_tinyint0006" + " for each row "
|
||||
+ "begin" + " update t_tinyint0006 set my_data=1;" + "end;";
|
||||
try (Connection conn = createConnection()) {
|
||||
ExecuteUtil.execute(conn, sqlTable);
|
||||
ExecuteUtil.execute(conn, sqlTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturningQuery() throws Exception {
|
||||
String returnString = "INSERT INTO CIMMIT (DATA_ENABLE) VALUES (1)";
|
||||
try (Connection conn = createConnection()) {
|
||||
PreparedStatement st = conn.prepareStatement(returnString, new String[] {"ID"});
|
||||
st.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchInsert() throws Exception {
|
||||
Properties props = new Properties();
|
||||
props.put("preparedStatementCacheQueries", "2");
|
||||
props.put("prepareThreshold", "2");
|
||||
props.put("fetchSize", "5");
|
||||
props.put("batchMode", "OFF");
|
||||
props.put("reWriteBatchedInserts", "true");
|
||||
try (Connection conn = TestUtil.openDB(props)) {
|
||||
for (int j = 1; j <= 1000; j++) {
|
||||
ExecuteUtil.execute(conn, "set session_timeout = 0;");
|
||||
ExecuteUtil.execute(conn, "drop table if exists t" + j);
|
||||
ExecuteUtil.execute(conn, "create table t" + j
|
||||
+ "(id int, id1 int, id2 int, id3 int, id4 int, id5 int, data varchar(2048));");
|
||||
String batchInsert = "insert into t" + j + " values (?,?,?,?,?,?,?)";
|
||||
PreparedStatement preparedStatement = conn.prepareStatement(batchInsert);
|
||||
for (int i = 1; i <= 1000; i++) {
|
||||
preparedStatement.setInt(1, 1);
|
||||
preparedStatement.setInt(2, i);
|
||||
preparedStatement.setInt(3, i);
|
||||
preparedStatement.setInt(4, i);
|
||||
preparedStatement.setInt(5, i);
|
||||
preparedStatement.setInt(6, i);
|
||||
preparedStatement.setString(7, "Huawei");
|
||||
preparedStatement.addBatch();
|
||||
}
|
||||
preparedStatement.executeBatch();
|
||||
preparedStatement.close();
|
||||
}
|
||||
// block
|
||||
}
|
||||
}
|
||||
|
||||
private static Connection createConnection() throws Exception {
|
||||
return TestUtil.openDB();
|
||||
}
|
||||
|
Reference in New Issue
Block a user