mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
support sharePreparedStatements option
This commit is contained in:
@@ -66,7 +66,7 @@ public final class ConnectionHolder {
|
||||
this.defaultHoldability = conn.getHoldability();
|
||||
this.defaultTransactionIsolation = conn.getTransactionIsolation();
|
||||
this.defaultAutoCommit = conn.getAutoCommit();
|
||||
|
||||
|
||||
this.underlyingAutoCommit = defaultAutoCommit;
|
||||
this.underlyingHoldability = defaultHoldability;
|
||||
this.underlyingTransactionIsolation = defaultTransactionIsolation;
|
||||
@@ -143,7 +143,15 @@ public final class ConnectionHolder {
|
||||
}
|
||||
|
||||
public boolean isPoolPreparedStatements() {
|
||||
return dataSource.isPoolPreparedStatements();
|
||||
boolean poolPreparedStatements = dataSource.isPoolPreparedStatements();
|
||||
if (poolPreparedStatements) {
|
||||
boolean transaction = !isUnderlyingAutoCommit();
|
||||
if (transaction && !dataSource.isSharePreparedStatements()) {
|
||||
poolPreparedStatements = false;
|
||||
}
|
||||
}
|
||||
|
||||
return poolPreparedStatements;
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
|
||||
@@ -119,6 +119,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
|
||||
private boolean testWhileIdle = DEFAULT_WHILE_IDLE;
|
||||
protected boolean poolPreparedStatements = false;
|
||||
protected boolean sharePreparedStatements = false;
|
||||
protected int maxPoolPreparedStatementPerConnectionSize = 10;
|
||||
|
||||
protected boolean inited = false;
|
||||
@@ -206,7 +207,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
if (transactionQueryTimeout <= 0) {
|
||||
return queryTimeout;
|
||||
}
|
||||
|
||||
|
||||
return transactionQueryTimeout;
|
||||
}
|
||||
|
||||
@@ -349,9 +350,21 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
}
|
||||
|
||||
public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
|
||||
if (maxPoolPreparedStatementPerConnectionSize > 0) {
|
||||
this.poolPreparedStatements = true;
|
||||
}
|
||||
|
||||
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
|
||||
}
|
||||
|
||||
public boolean isSharePreparedStatements() {
|
||||
return sharePreparedStatements;
|
||||
}
|
||||
|
||||
public void setSharePreparedStatements(boolean sharePreparedStatements) {
|
||||
this.sharePreparedStatements = sharePreparedStatements;
|
||||
}
|
||||
|
||||
public void incrementDupCloseCount() {
|
||||
dupCloseCount.incrementAndGet();
|
||||
}
|
||||
@@ -436,7 +449,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
}
|
||||
|
||||
public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) {
|
||||
this.maxPoolPreparedStatementPerConnectionSize = maxOpenPreparedStatements;
|
||||
this.setMaxPoolPreparedStatementPerConnectionSize(maxOpenPreparedStatements);
|
||||
}
|
||||
|
||||
public boolean isLogAbandoned() {
|
||||
@@ -1044,9 +1057,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
|
||||
void initStatement(PoolableConnection conn, Statement stmt) throws SQLException {
|
||||
boolean transaction = !conn.getConnectionHolder().isUnderlyingAutoCommit();
|
||||
|
||||
|
||||
int queryTimeout = transaction ? getTransactionQueryTimeout() : getQueryTimeout();
|
||||
|
||||
|
||||
if (queryTimeout > 0) {
|
||||
stmt.setQueryTimeout(queryTimeout);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public interface DruidAbstractDataSourceMBean {
|
||||
long getStartTransactionCount();
|
||||
|
||||
int getQueryTimeout();
|
||||
|
||||
|
||||
int getTransactionQueryTimeout();
|
||||
|
||||
String getValidationQuery();
|
||||
@@ -66,13 +66,13 @@ public interface DruidAbstractDataSourceMBean {
|
||||
List<String> getFilterClassNames();
|
||||
|
||||
boolean isTestOnBorrow();
|
||||
|
||||
|
||||
void setTestOnBorrow(boolean testOnBorrow);
|
||||
|
||||
boolean isTestOnReturn();
|
||||
|
||||
|
||||
boolean isTestWhileIdle();
|
||||
|
||||
|
||||
void setTestWhileIdle(boolean testWhileIdle);
|
||||
|
||||
boolean isDefaultAutoCommit();
|
||||
@@ -85,6 +85,8 @@ public interface DruidAbstractDataSourceMBean {
|
||||
|
||||
boolean isPoolPreparedStatements();
|
||||
|
||||
boolean isSharePreparedStatements();
|
||||
|
||||
long getMaxWait();
|
||||
|
||||
int getMinIdle();
|
||||
@@ -102,7 +104,7 @@ public interface DruidAbstractDataSourceMBean {
|
||||
long getRemoveAbandonedCount();
|
||||
|
||||
boolean isLogAbandoned();
|
||||
|
||||
|
||||
void setLogAbandoned(boolean logAbandoned);
|
||||
|
||||
long getDupCloseCount();
|
||||
|
||||
@@ -167,11 +167,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
public PreparedStatement prepareStatement(String sql) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -179,7 +180,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
try {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -203,12 +204,13 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M2, resultSetType,
|
||||
resultSetConcurrency);
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -217,7 +219,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType,
|
||||
resultSetConcurrency));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -241,12 +243,13 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
int resultSetHoldability) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M3, resultSetType,
|
||||
resultSetConcurrency, resultSetHoldability);
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -256,7 +259,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
resultSetConcurrency,
|
||||
resultSetHoldability));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -279,10 +282,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes);
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes);
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -290,7 +295,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
try {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -313,10 +318,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames);
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames);
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -324,7 +331,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
try {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -347,10 +354,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys);
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys);
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -358,7 +367,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
try {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -383,11 +392,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1);
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -395,7 +405,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
try {
|
||||
stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -420,10 +430,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_2, resultSetType,
|
||||
resultSetConcurrency, resultSetHoldability);
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -433,7 +445,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
resultSetConcurrency,
|
||||
resultSetHoldability));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
@@ -457,10 +469,12 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
checkOpen();
|
||||
|
||||
PreparedStatementHolder stmtHolder = null;
|
||||
|
||||
PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_3, resultSetType,
|
||||
resultSetConcurrency);
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
|
||||
boolean poolPreparedStatements = holder.isPoolPreparedStatements();
|
||||
|
||||
if (poolPreparedStatements) {
|
||||
stmtHolder = holder.getStatementPool().get(key);
|
||||
}
|
||||
|
||||
@@ -469,7 +483,7 @@ public class PoolableConnection implements PooledConnection, Connection {
|
||||
stmtHolder = new PreparedStatementHolder(key,
|
||||
conn.prepareCall(sql, resultSetType, resultSetConcurrency));
|
||||
holder.getDataSource().incrementPreparedStatementCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
if (poolPreparedStatements) {
|
||||
holder.getStatementPool().put(stmtHolder);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.alibaba.druid.bvt.pool;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.alibaba.druid.mock.MockPreparedStatement;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.stat.DruidDataSourceStatManager;
|
||||
|
||||
public class TestSharePreparedStatements extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
|
||||
}
|
||||
|
||||
public void test_sharePreparedStatements() throws Exception {
|
||||
|
||||
// sharePreparedStatements
|
||||
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:mock:xxx");
|
||||
dataSource.setMaxPoolPreparedStatementPerConnectionSize(30);
|
||||
|
||||
String sql = "SELECT 1";
|
||||
|
||||
MockPreparedStatement mockStmt = null;
|
||||
{
|
||||
Connection conn = dataSource.getConnection();
|
||||
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
mockStmt = stmt.unwrap(MockPreparedStatement.class);
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
rs.next();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
{
|
||||
Connection conn = dataSource.getConnection();
|
||||
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
Assert.assertEquals(mockStmt, stmt.unwrap(MockPreparedStatement.class));
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
rs.next();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
{
|
||||
Connection conn = dataSource.getConnection();
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
Assert.assertEquals(true, mockStmt != stmt.unwrap(MockPreparedStatement.class));
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
rs.next();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
{
|
||||
Connection conn = dataSource.getConnection();
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
Assert.assertEquals(true, mockStmt != stmt.unwrap(MockPreparedStatement.class));
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
rs.next();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ public class PerfTest extends TestCase {
|
||||
public void test_perf() throws Exception {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// perf("SELECT * FROM my_table WHERE TRUNC(SYSDATE) = DATE '2002-10-03';");
|
||||
perfOracle("SELECT * FROM T");
|
||||
perfMySql("SELECT * FROM T");
|
||||
perfOracle("SELECT a.ID, a.GMT_CREATE, a.GMT_MODIFIED, a.COMPANY_NAME, a.BIZ_TYPE , b.SERVICE_TYPE, b.SERVICE_LEVEL, b.BUSINESS_ROLE, a.STATUS, a.RECOMMENDED , a.COUNTRY, a.PROVINCE, a.CITY, a.ADDRESS, a.ZIP , a.LOGO_FILE, a.EMAIL, a.BRIEF_PROFILE, a.DOMAIN_ID, a.IS_PASS_AV , a.KEYWORDS, a.PROVIDE_PRODUCTS, a.PURCHASE_PRODUCTS, a.BRAND_NAME, a.PROMOTION_VALUE , a.OWNER_MEMBER_ID, a.OWNER_SEQ, a.EMPLOYEES_COUNT, a.ANNUAL_REVENUE, a.HOMEPAGE_URL , a.REG_ADDRESS, a.TRADE_REGION, a.TRADE_REGION_USER, a.REG_CAPITAL, a.OWNERSHIP_TYPE , a.ESTABLISHED_YEAR, a.PRINCIPAL, a.ANNUAL_PURCHASE, a.CERTIFICATION, a.CERTIFICATION_2 , a.CONTACT_MANUFACTURING, a.YEARS_OEM, b.STAGE, a.VIDEO_PATH, a.ABOUTUS_IMAGE_PATH , a.ABOUTUS_IMAGE_TITLE, a.CHINESE_NAME, a.IMAGE_VERSION FROM COMPANY a, VACCOUNT b WHERE a.ID = b.ID AND a.id IN (?)");
|
||||
perfMySql("SELECT a.ID, a.GMT_CREATE, a.GMT_MODIFIED, a.COMPANY_NAME, a.BIZ_TYPE , b.SERVICE_TYPE, b.SERVICE_LEVEL, b.BUSINESS_ROLE, a.STATUS, a.RECOMMENDED , a.COUNTRY, a.PROVINCE, a.CITY, a.ADDRESS, a.ZIP , a.LOGO_FILE, a.EMAIL, a.BRIEF_PROFILE, a.DOMAIN_ID, a.IS_PASS_AV , a.KEYWORDS, a.PROVIDE_PRODUCTS, a.PURCHASE_PRODUCTS, a.BRAND_NAME, a.PROMOTION_VALUE , a.OWNER_MEMBER_ID, a.OWNER_SEQ, a.EMPLOYEES_COUNT, a.ANNUAL_REVENUE, a.HOMEPAGE_URL , a.REG_ADDRESS, a.TRADE_REGION, a.TRADE_REGION_USER, a.REG_CAPITAL, a.OWNERSHIP_TYPE , a.ESTABLISHED_YEAR, a.PRINCIPAL, a.ANNUAL_PURCHASE, a.CERTIFICATION, a.CERTIFICATION_2 , a.CONTACT_MANUFACTURING, a.YEARS_OEM, b.STAGE, a.VIDEO_PATH, a.ABOUTUS_IMAGE_PATH , a.ABOUTUS_IMAGE_TITLE, a.CHINESE_NAME, a.IMAGE_VERSION FROM COMPANY a, VACCOUNT b WHERE a.ID = b.ID AND a.id IN (?)");
|
||||
// perf(loadSql("bvt/parser/oracle-23.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user