[jdbc] Add support for SQL:2008 FETCH FIRST n ROWS ONLY for Scans (#1373)

This commit is contained in:
@FranckPachot 2019-11-13 20:50:44 +01:00 коммит произвёл Sean Busbey
Родитель 6c8c7fc503
Коммит 25724e8f2c
3 изменённых файлов: 34 добавлений и 11 удалений

Просмотреть файл

@ -82,7 +82,11 @@ public class JdbcDBClient extends DB {
/** The field name prefix in the table. */
public static final String COLUMN_PREFIX = "FIELD";
private boolean sqlserver = false;
/** SQL:2008 standard: FETCH FIRST n ROWS after the ORDER BY. */
private boolean sqlansiScans = false;
/** SQL Server before 2012: TOP n after the SELECT. */
private boolean sqlserverScans = false;
private List<Connection> conns;
private boolean initialized = false;
private Properties props;
@ -184,8 +188,6 @@ public class JdbcDBClient extends DB {
String passwd = props.getProperty(CONNECTION_PASSWD, DEFAULT_PROP);
String driver = props.getProperty(DRIVER_CLASS);
this.jdbcFetchSize = getIntProperty(props, JDBC_FETCH_SIZE);
this.batchSize = getIntProperty(props, DB_BATCH_SIZE);
@ -193,9 +195,23 @@ public class JdbcDBClient extends DB {
this.batchUpdates = getBoolProperty(props, JDBC_BATCH_UPDATES, false);
try {
// The SQL Syntax for Scan depends on the DB engine
// - SQL:2008 standard: FETCH FIRST n ROWS after the ORDER BY
// - SQL Server before 2012: TOP n after the SELECT
// - others (MySQL,MariaDB, PostgreSQL before 8.4)
// TODO: check product name and version rather than driver name
if (driver != null) {
if (driver.contains("sqlserver")) {
sqlserver = true;
sqlserverScans = true;
sqlansiScans = false;
}
if (driver.contains("oracle")) {
sqlserverScans = false;
sqlansiScans = true;
}
if (driver.contains("postgres")) {
sqlserverScans = false;
sqlansiScans = true;
}
Class.forName(driver);
}
@ -308,7 +324,7 @@ public class JdbcDBClient extends DB {
private PreparedStatement createAndCacheScanStatement(StatementType scanType, String key)
throws SQLException {
String select = dbFlavor.createScanStatement(scanType, key, sqlserver);
String select = dbFlavor.createScanStatement(scanType, key, sqlserverScans, sqlansiScans);
PreparedStatement scanStatement = getShardConnectionByKey(key).prepareStatement(select);
if (this.jdbcFetchSize > 0) {
scanStatement.setFetchSize(this.jdbcFetchSize);
@ -357,9 +373,11 @@ public class JdbcDBClient extends DB {
if (scanStatement == null) {
scanStatement = createAndCacheScanStatement(type, startKey);
}
if (sqlserver) {
// SQL Server TOP syntax is at first
if (sqlserverScans) {
scanStatement.setInt(1, recordcount);
scanStatement.setString(2, startKey);
// FETCH FIRST and LIMIT are at the end
} else {
scanStatement.setString(1, startKey);
scanStatement.setInt(2, recordcount);

Просмотреть файл

@ -65,5 +65,6 @@ public abstract class DBFlavor {
/**
* Create and return a SQL statement for scanning data.
*/
public abstract String createScanStatement(StatementType scanType, String key, boolean sqlserver);
public abstract String createScanStatement(StatementType scanType, String key,
boolean sqlserverScans, boolean sqlansiScans);
}

Просмотреть файл

@ -84,9 +84,9 @@ public class DefaultDBFlavor extends DBFlavor {
}
@Override
public String createScanStatement(StatementType scanType, String key, boolean sqlserver) {
public String createScanStatement(StatementType scanType, String key, boolean sqlserverScans, boolean sqlansiScans) {
StringBuilder select;
if (sqlserver) {
if (sqlserverScans) {
select = new StringBuilder("SELECT TOP (?) * FROM ");
} else {
select = new StringBuilder("SELECT * FROM ");
@ -97,8 +97,12 @@ public class DefaultDBFlavor extends DBFlavor {
select.append(" >= ?");
select.append(" ORDER BY ");
select.append(JdbcDBClient.PRIMARY_KEY);
if (!sqlserver) {
select.append(" LIMIT ?");
if (!sqlserverScans) {
if (sqlansiScans) {
select.append(" FETCH FIRST ? ROWS ONLY");
} else {
select.append(" LIMIT ?");
}
}
return select.toString();
}