spring mysql防注入攻击_【spring】(填坑)sql注入攻击 - 持久层参数化

结果

填坑失败,并没有看懂是如何检测sql攻击的。

只能说的是:建议都使用参数化传递sql语句参数。(所以,用hibernate、mybatis等框架的真不用太担心sql攻击问题。)

前言

在上文中的demo是:

正确sql:

select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c where c.child_id= '1'

攻击sql:

select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c where c.child_id= '1';delete from child where child_id='1';--'

执行抛出的异常:

java.sql.SQLException: ORA-00911: 无效字符

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)

at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)

at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)

at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)

at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)

at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)

at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:861)

at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1145)

at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1267)

at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)

at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3493)

at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1203)

at com.vergilyn.test.sh.dao.JdbcTemplateDao.injectionAttack(JdbcTemplateDao.java:49)

at com.lyn.Junit.TestJdbc.testInjectionAttack(TestJdbc.java:35)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

最后给出的错误结论:oracle驱动jar中处理对sql注入攻击进行了处理。

为什么会得出错误结论:

1、肯定是技术不过关、分析不仔细。

2、没有严格去验证,单纯的测试了jdbc、jdbcTemplate、Hibernate就得出了此结论。

异常原因:

根据异常提示,我去看了下ojdbc5.jar中的源码。  即核心是oracle/jdbc/driver/T4CMAREngine.class中的unmarshalUB2()、buffer2Value(byte var)。

主要是在buffer2Value()方法返回long的值是911,然后ojdbc在后面根据此值抛出以上异常。

表示实在看不懂buffer2Value()及其内部含义,但简单理解就是在攻击sql中出现了”;”分号,导致抛出此异常。

一、验证非参数话会存在sql注入攻击(jdbcTemplate测试)

@Test

@Rollback()

public void testSqlInjectionAttack(){ //结论: jdbcTemplate不用参数化会存在sql攻击问题。

String id = "1"; //正确参数

// id = "1' or 1=1 --"; //sql攻击参数

Object rs = jdbcDao.sqlInjectionAttack(id);

System.out.println(JSON.toJSONString(rs));

}

public Object sqlInjectionAttack(String id){

String sql = "select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c";

sql += "where c.child_id= '"+id+"'";

return this.jdbcTemplate.query(sql,new BeanPropertyRowMapper(Child.class));

}

说明:1、正确的是返回一个Child对象。攻击sql则返回List对象。

2、用的方法是query(…)。如果是queryForXXX(…),可能会抛异常:org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 10

sql攻击结果:

14f418cdb2f7e68c98f2a055b03e211d.png

二、验证参数化查询防止sql注入攻击

@Test

@Rollback()

public void solveSqlInjectionAttack(){ //参数化sql防止sql注入攻击

String id = "1"; //正确参数

// id = "1' or 1=1 --"; //sql攻击参数

Object rs = jdbcTemplateDao.solveSqlInjectionAttack(id);

System.out.println(JSON.toJSONString(rs));

}

public Object solveSqlInjectionAttack(String id){

String sql = "select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c";

sql += "where c.child_id= ?";

return this.jdbcTemplate.query(sql,new Object[]{id},new BeanPropertyRowMapper(Child.class));

}

正确sql结果:

6c0b89c497a740bbb8b9ae539a98a727.png

攻击sql结果:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

信息: Rolled back transaction for test context [DefaultTestContext@1cfddcd testClass = JdbcTemplateTest, testInstance = com.vergilyn.persistence.test.jdbcTemplate.JdbcTemplateTest@1ead226, testMethod = solveSqlInjectionAttack@JdbcTemplateTest, testException = org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c where c.child_id= ?]; ORA-01722: 无效数字

; nested exception is java.sql.SQLException: ORA-01722: 无效数字

, mergedContextConfiguration = [MergedContextConfiguration@18add92 testClass = JdbcTemplateTest, locations = '{classpath:jdbcTemplate/jdbcTemplate-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].

十二月 31, 2016 12:42:03 上午 org.springframework.context.support.AbstractApplicationContext doClose

信息: Closing org.springframework.context.support.GenericApplicationContext@1f12030: startup date [Sat Dec 31 00:41:44 CST 2016]; root of context hierarchy

org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [select c.child_id childId,c.child_name,c.child_age childAge,c.parent_id parentId from child c where c.child_id= ?]; ORA-01722: 无效数字

; nested exception is java.sql.SQLException: ORA-01722: 无效数字

at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:243)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)

at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660)

at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695)

at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:727)

at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:737)

at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:787)

at com.vergilyn.persistence.jdbcTemplate.JdbcTemplateDao.solveSqlInjectionAttack(JdbcTemplateDao.java:42)

at com.vergilyn.persistence.test.jdbcTemplate.JdbcTemplateTest.solveSqlInjectionAttack(JdbcTemplateTest.java:30)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)

at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)

at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)

at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)

at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)

at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)

at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)

at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)

at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)

at org.junit.runner.JUnitCore.run(JUnitCore.java:137)

at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)

at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)

at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)

at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)

Caused by: java.sql.SQLException: ORA-01722: 无效数字

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)

at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)

at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)

at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)

at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)

at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)

at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:861)

at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1145)

at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1267)

at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)

at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3493)

at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1203)

at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)

at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)

at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)

at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:703)

at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:644)

... 34 more异常信息

以上结果是因为,数据库中的CHILD_ID的类型是NUMBER,传入的参数却是String。

当我把CHILD_ID的类型修改为:varchar2时,sql可正常执行。但sql查询结果是null。因为,数据库记录中并没有一个CHILD_ID = ”1' or 1=1 --“

三、部分源码 (填坑失败,后面的代码逻辑实在难看懂。)

/**

* Query using a prepared statement, allowing for a PreparedStatementCreator

* and a PreparedStatementSetter. Most other query methods use this method,

* but application code will always work with either a creator or a setter.

* @param psc Callback handler that can create a PreparedStatement given a

* Connection

* @param pss object that knows how to set values on the prepared statement.

* If this is null, the SQL will be assumed to contain no bind parameters.

* @param rse object that will extract results.

* @return an arbitrary result object, as returned by the ResultSetExtractor

* @throws DataAccessException if there is any problem

*/

public T query(

PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)

throws DataAccessException {

Assert.notNull(rse, "ResultSetExtractor must not be null");

logger.debug("Executing prepared SQL query");

return execute(psc, new PreparedStatementCallback() { //line:695

@Override

public T doInPreparedStatement(PreparedStatement ps) throws SQLException {

ResultSet rs = null;

try {

if (pss != null) {

pss.setValues(ps);

}

rs = ps.executeQuery(); // 抛出异常方法 - 02ResultSet rsToUse = rs;

if (nativeJdbcExtractor != null) {

rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);

}

return rse.extractData(rsToUse);

}

finally {

JdbcUtils.closeResultSet(rs);

if (pss instanceof ParameterDisposer) {

((ParameterDisposer) pss).cleanupParameters();

}

}

}

});

}

//-------------------------------------------------------------------------

// Methods dealing with prepared statements

//-------------------------------------------------------------------------

@Override

public T execute(PreparedStatementCreator psc, PreparedStatementCallback action)

throws DataAccessException {

Assert.notNull(psc, "PreparedStatementCreator must not be null");

Assert.notNull(action, "Callback object must not be null");

if (logger.isDebugEnabled()) {

String sql = getSql(psc);

logger.debug("Executing prepared SQL statement" + (sql != null ? "[" + sql + "]" : ""));

}

Connection con = DataSourceUtils.getConnection(getDataSource());

PreparedStatement ps = null;

try {

Connection conToUse = con;

if (this.nativeJdbcExtractor != null &&

this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {

conToUse = this.nativeJdbcExtractor.getNativeConnection(con);

}

ps = psc.createPreparedStatement(conToUse);

applyStatementSettings(ps);

PreparedStatement psToUse = ps;

if (this.nativeJdbcExtractor != null) {

psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);

}

T result = action.doInPreparedStatement(psToUse); // 抛出异常方法 - 01

handleWarnings(ps);

return result;

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

if (psc instanceof ParameterDisposer) {

((ParameterDisposer) psc).cleanupParameters();

}

String sql = getSql(psc);

psc = null;

JdbcUtils.closeStatement(ps);

ps = null;

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex); //line: 660

}

finally {

if (psc instanceof ParameterDisposer) {

((ParameterDisposer) psc).cleanupParameters();

}

JdbcUtils.closeStatement(ps);

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

其中抛异常的方法是: at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660)

方法中的>>>> T result = action.doInPreparedStatement(psToUse);

20ff6b2f2e91b9b9c804912022737031.png

此处的action.doInPreparedStatement(psToUse)实际调用的就是上面 - 匿名内部类中定义的。

// 抛出异常 - 02 代码

public ResultSet executeQuery() throws SQLException {

this.checkOpen();

try {

return DelegatingResultSet.wrapResultSet(this, ((PreparedStatement)this._stmt).executeQuery());

} catch (SQLException var2) {

this.handleException(var2);

throw new AssertionError();

}

}

出现异常方法:((PreparedStatement)this._stmt).executeQuery()。  this._stmt = OraclePreparedStatementWrapper.class

// OraclePreparedStatementWrapper.class

public ResultSet executeQuery() throws SQLException {

return this.preparedStatement.executeQuery(); //this.preparedStatement = T4CPreparedStatement.class

}class T4CPreparedStatement extends OraclePreparedStatement;

// OraclePreparedStatement.classpublic ResultSet executeQuery() throws SQLException {

PhysicalConnection var1 = this.connection;

synchronized(this.connection) {

this.executionType = 1;

this.executeInternal(); // 异常方法 - 03

if(this.userRsetType == 1) {

this.currentResultSet = new OracleResultSetImpl(this.connection, this);

return this.currentResultSet;

} else {

if(this.scrollRset == null) {

this.currentResultSet = new OracleResultSetImpl(this.connection, this);

this.scrollRset = this.currentResultSet;

}

return this.scrollRset;

}

}

}

int executeInternal() throws SQLException {

this.noMoreUpdateCounts = false;

this.ensureOpen();

if(this.currentRank > 0 && this.m_batchStyle == 2) {

SQLException var3 = DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), 81, "batch must be either executed or cleared");

var3.fillInStackTrace();

throw var3;

} else {

boolean var1 = this.userRsetType == 1;

this.prepareForNewResults(true, false);

this.processCompletedBindRow(this.sqlKind == 0?1:this.batch, false);

if(!var1 && !this.scrollRsetTypeSolved) {

return this.doScrollPstmtExecuteUpdate() + this.prematureBatchCount;

} else {

this.doExecuteWithTimeout(); // 异常方法 - 04

boolean var2 = this.prematureBatchCount != 0 && this.validRows > 0;

if(!var1) {

this.currentResultSet = new OracleResultSetImpl(this.connection, this);

this.scrollRset = ResultSetUtil.createScrollResultSet(this, this.currentResultSet, this.realRsetType);

if(!this.connection.accumulateBatchResult) {

var2 = false;

}

}

if(var2) {

this.validRows += this.prematureBatchCount;

this.prematureBatchCount = 0;

}

return this.validRows;

}

}

}

void doExecuteWithTimeout() throws SQLException {

try {

this.cleanOldTempLobs();

this.connection.registerHeartbeat();

this.rowsProcessed = 0;

SQLException var1;

if(this.sqlKind == 0) {

if(this.connection.j2ee13Compliant && this.executionType == 2) {

var1 = DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), 129);

var1.fillInStackTrace();

throw var1;

}

this.connection.needLine();

if(!this.isOpen) {

this.connection.open(this);

this.isOpen = true;

}

if(this.queryTimeout != 0) {

try {

this.connection.getTimeout().setTimeout((long)(this.queryTimeout * 1000), this);

this.executeMaybeDescribe();

} finally {

this.connection.getTimeout().cancelTimeout();

}

} else {

this.executeMaybeDescribe(); // 异常方法 - 05

}

this.checkValidRowsStatus();

if(this.serverCursor) {

this.adjustGotLastBatch();

}

} else {

if(this.connection.j2ee13Compliant && this.sqlKind != 1 && this.sqlKind != 4 && this.executionType == 1) {

var1 = DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), 128);

var1.fillInStackTrace();

throw var1;

}

++this.currentRank;

if(this.currentRank >= this.batch) {

try {

this.connection.needLine();

if(!this.isOpen) {

this.connection.open(this);

this.isOpen = true;

}

if(this.queryTimeout != 0) {

this.connection.getTimeout().setTimeout((long)(this.queryTimeout * 1000), this);

}

this.isExecuting = true;

this.executeForRows(false);

} catch (SQLException var14) {

this.needToParse = true;

if(this.batch > 1) {

this.clearBatch();

int[] var2;

int var3;

if(this.numberOfExecutedElementsInBatch != -1 && this.numberOfExecutedElementsInBatch < this.batch) {

var2 = new int[this.numberOfExecutedElementsInBatch];

for(var3 = 0; var3 < var2.length; ++var3) {

var2[var3] = -2;

}

} else {

var2 = new int[this.batch];

for(var3 = 0; var3 < var2.length; ++var3) {

var2[var3] = -3;

}

}

BatchUpdateException var17 = DatabaseError.createBatchUpdateException(var14, var2.length, var2);

var17.fillInStackTrace();

throw var17;

}

this.resetCurrentRowBinders();

throw var14;

} finally {

if(this.queryTimeout != 0) {

this.connection.getTimeout().cancelTimeout();

}

this.currentRank = 0;

this.isExecuting = false;

this.checkValidRowsStatus();

}

}

}

} catch (SQLException var16) {

this.resetOnExceptionDuringExecute();

throw var16;

}

this.connection.registerHeartbeat();

}

void executeMaybeDescribe() throws SQLException

{

int i = 1;

if (this.rowPrefetchChanged)

{

if ((this.streamList == null) && (this.rowPrefetch != this.definesBatchSize)) {

this.needToPrepareDefineBuffer = true;

}

this.rowPrefetchChanged = false;

}

if (!this.needToPrepareDefineBuffer)

{

if (this.accessors == null)

{

this.needToPrepareDefineBuffer = true;

} else if (this.columnsDefinedByUser) {

this.needToPrepareDefineBuffer = (!checkAccessorsUsable());

}

}

boolean bool = false;

try

{

this.isExecuting = true;

if (this.needToPrepareDefineBuffer)

{

if (!this.columnsDefinedByUser)

{

executeForDescribe();// 异常方法 – 06 实际是调用T4CPreparedStatement.class中的实现方法

bool = true;

if (this.aFetchWasDoneDuringDescribe) {

i = 0;

}

}

if (this.needToPrepareDefineBuffer)

{

prepareAccessors();

}

}

int j = this.accessors.length;

for (int k = this.numberOfDefinePositions; k < j; k++)

{

Accessor localAccessor = this.accessors[k];

if (localAccessor != null)

localAccessor.rowSpaceIndicator = null;

}

if (i != 0) {

executeForRows(bool);

}

}

catch (SQLException localSQLException)

{

this.needToParse = true;

throw localSQLException;

}

finally

{

this.isExecuting = false;

}

}

// T4CPreparedStatement.class

void executeForDescribe() throws SQLException {

this.t4Connection.assertLoggedOn("oracle.jdbc.driver.T4CPreparedStatement.execute_for_describe");

this.cleanOldTempLobs();

try {

if(this.t4Connection.useFetchSizeWithLongColumn) {

this.doOall8(true, true, true, true, false);

} else {

this.doOall8(true, true, false, true, this.definedColumnType != null);// 异常 - 07

}

} catch (SQLException var8) {

throw var8; // ORA-01722: 无效数字} catch (IOException var9) {

((T4CConnection)this.connection).handleIOException(var9);

SQLException var2 = DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), var9);

var2.fillInStackTrace();

throw var2;

} finally {

this.rowsProcessed = this.t4Connection.all8.rowsProcessed;

this.validRows = this.t4Connection.all8.getNumRows();

}

this.needToParse = false;

this.implicitDefineForLobPrefetchDone = false;

this.aFetchWasDoneDuringDescribe = false;

if(this.t4Connection.all8.aFetchWasDone) {

this.aFetchWasDoneDuringDescribe = true;

this.rowPrefetchInLastFetch = this.rowPrefetch;

}

for(int var1 = 0; var1 < this.numberOfDefinePositions; ++var1) {

this.accessors[var1].initMetadata();

}

this.needToPrepareDefineBuffer = false;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值