arminw 2005/06/04 07:13:43
Modified: src/java/org/apache/ojb/broker/accesslayer Tag:
OJB_1_0_RELEASE JdbcAccessImpl.java
StatementManager.java StatementManagerIF.java
StatementsForClassIF.java
StatementsForClassImpl.java
src/java/org/apache/ojb/broker/platforms Tag:
OJB_1_0_RELEASE Platform.java
PlatformHsqldbImpl.java PlatformSapdbImpl.java
Log:
replace Platform#isCallableStatement method and introduce an contract between
JdbcAccess and StatementManager to detect the use of stored procedures.
Revision Changes Path
No revision
No revision
1.22.2.6 +59 -20
db-ojb/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java
Index: JdbcAccessImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java,v
retrieving revision 1.22.2.5
retrieving revision 1.22.2.6
diff -u -r1.22.2.5 -r1.22.2.6
--- JdbcAccessImpl.java 26 Apr 2005 03:41:35 -0000 1.22.2.5
+++ JdbcAccessImpl.java 4 Jun 2005 14:13:43 -0000 1.22.2.6
@@ -177,7 +177,7 @@
{
final String sql =
this.broker.serviceSqlGenerator().getPreparedDeleteStatement(query, cld);
stmt =
broker.serviceStatementManager().getPreparedStatement(cld, sql,
- false, StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE);
+ false, StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE,
cld.getDeleteProcedure()!=null);
broker.serviceStatementManager().bindStatement(stmt, query, cld,
1);
if (logger.isDebugEnabled())
@@ -316,12 +316,13 @@
{
final int queryFetchSize = query.getFetchSize();
final String sql =
broker.serviceSqlGenerator().getPreparedSelectStatement(query, cld);
+ final boolean isStoredProcedure = isStoredProcedure(sql);
final PreparedStatement stmt;
stmt =
broker.serviceStatementManager().getPreparedStatement(cld, sql,
- scrollable, queryFetchSize);
+ scrollable, queryFetchSize, isStoredProcedure);
ResultSet rs;
- if (getPlatform().isCallableStatement(stmt))
+ if (isStoredProcedure)
{
// Query implemented as a stored procedure, which must
return a result set.
// Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
@@ -404,15 +405,16 @@
throws PersistenceBrokerException
{
if (logger.isDebugEnabled()) logger.debug("executeSQL: " +
sqlStatement);
+ final boolean isStoredprocedure = isStoredProcedure(sqlStatement);
StatementManagerIF stmtMan = broker.serviceStatementManager();
ResultSetAndStatement retval = null;
try
{
final PreparedStatement stmt = stmtMan.getPreparedStatement(cld,
sqlStatement,
- scrollable,
StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET);
+ scrollable,
StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET, isStoredprocedure);
ResultSet rs;
- if (getPlatform().isCallableStatement(stmt))
+ if (isStoredprocedure)
{
// Query implemented as a stored procedure, which must
return a result set.
// Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
@@ -492,7 +494,7 @@
try
{
stmt = stmtMan.getPreparedStatement(cld, sqlStatement,
- Query.NOT_SCROLLABLE,
StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE);
+ Query.NOT_SCROLLABLE,
StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE, isStoredProcedure(sqlStatement));
index = stmtMan.bindValues(stmt, values1, 1);
index = stmtMan.bindValues(stmt, values2, index);
result = stmt.executeUpdate();
@@ -630,18 +632,12 @@
logger.error("getSelectByPKStatement returned a null
statement");
throw new PersistenceBrokerException("getSelectByPKStatement
returned a null statement");
}
- broker.serviceStatementManager().bindSelect(stmt, oid, cld);
-
- if (getPlatform().isCallableStatement(stmt))
- {
- // If this is a stored procedure call, first argument is
ResultSet
- stmt.execute();
- rs = (ResultSet) ((CallableStatement) stmt).getObject(1);
- }
- else
- {
- rs = stmt.executeQuery();
- }
+ /*
+ arminw: currently a select by PK could never be a stored
procedure,
+ thus we can always set 'false'. Is this correct??
+ */
+ broker.serviceStatementManager().bindSelect(stmt, oid, cld,
false);
+ rs = stmt.executeQuery();
// data available read object, else return null
if (rs.next())
@@ -716,7 +712,7 @@
{
// If the procedure descriptor is null or has no return values or
// if the statement is not a callable statment, then we're done.
- if ((proc == null) || (!proc.hasReturnValues()) ||
(!getPlatform().isCallableStatement(stmt)))
+ if ((proc == null) || (!proc.hasReturnValues()))
{
return;
}
@@ -800,4 +796,47 @@
throw new PersistenceBrokerSQLException(msg, e);
}
}
+
+ /**
+ * Check if the specified sql-string is a stored procedure
+ * or not.
+ * @param sql The sql query to check
+ * @return <em>True</em> if the query is a stored procedure, else
<em>false</em> is returned.
+ */
+ protected boolean isStoredProcedure(String sql)
+ {
+ /*
+ Stored procedures start with
+ {?= call <procedure-name>[<arg1>,<arg2>, ...]}
+ or
+ {call <procedure-name>[<arg1>,<arg2>, ...]}
+ but also statements with white space like
+ { ?= call <procedure-name>[<arg1>,<arg2>, ...]}
+ are possible.
+ */
+ int k = 0, i = 0;
+ char c;
+ while(k < 3 && i < sql.length())
+ {
+ c = sql.charAt(i);
+ if(c != ' ')
+ {
+ switch (k)
+ {
+ case 0:
+ if(c != '{') return false;
+ break;
+ case 1:
+ if(c != '?' && c != 'c') return false;
+ break;
+ case 2:
+ if(c != '=' && c != 'a') return false;
+ break;
+ }
+ k++;
+ }
+ i++;
+ }
+ return true;
+ }
}
1.47.2.5 +20 -6
db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementManager.java
Index: StatementManager.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementManager.java,v
retrieving revision 1.47.2.4
retrieving revision 1.47.2.5
diff -u -r1.47.2.4 -r1.47.2.5
--- StatementManager.java 26 Apr 2005 03:41:35 -0000 1.47.2.4
+++ StatementManager.java 4 Jun 2005 14:13:43 -0000 1.47.2.5
@@ -451,7 +451,7 @@
/**
* Binds the Identities Primary key values to the statement.
*/
- public void bindSelect(PreparedStatement stmt, Identity oid,
ClassDescriptor cld) throws SQLException
+ public void bindSelect(PreparedStatement stmt, Identity oid,
ClassDescriptor cld, boolean callableStmt) throws SQLException
{
ValueContainer[] values = null;
int i = 0;
@@ -463,7 +463,7 @@
}
try
{
- if (m_platform.isCallableStatement(stmt))
+ if(callableStmt)
{
// First argument is the result set
m_platform.registerOutResultSet((CallableStatement) stmt, 1);
@@ -601,12 +601,12 @@
* return a generic Statement for the given ClassDescriptor
*/
public PreparedStatement getPreparedStatement(ClassDescriptor cds,
String sql,
- boolean scrollable, int
explicitFetchSizeHint)
+ boolean scrollable, int
explicitFetchSizeHint, boolean callableStmt)
throws PersistenceBrokerException
{
try
{
- return
cds.getStatementsForClass(m_conMan).getPreparedStmt(m_conMan.getConnection(),
sql, scrollable, explicitFetchSizeHint);
+ return
cds.getStatementsForClass(m_conMan).getPreparedStmt(m_conMan.getConnection(),
sql, scrollable, explicitFetchSizeHint, callableStmt);
}
catch (LookupException e)
{
@@ -709,10 +709,24 @@
// Figure out if we are using a callable statement. If we are, then
we
// will need to register one or more output parameters.
CallableStatement callable = null;
- if (m_platform.isCallableStatement(stmt))
+ try
{
callable = (CallableStatement) stmt;
}
+ catch(Exception e)
+ {
+ m_log.error("Error while bind values for class '" + (cld != null
? cld.getClassNameOfObject() : null)
+ + "', using stored procedure: "+ proc, e);
+ if(e instanceof SQLException)
+ {
+ throw (SQLException) e;
+ }
+ else
+ {
+ throw new PersistenceBrokerException("Unexpected error while
bind values for class '"
+ + (cld != null ? cld.getClassNameOfObject() : null)
+ "', using stored procedure: "+ proc);
+ }
+ }
// If we have a return value, then register it.
if ((proc.hasReturnValue()) && (callable != null))
1.10.2.2 +5 -3
db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementManagerIF.java
Index: StatementManagerIF.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementManagerIF.java,v
retrieving revision 1.10.2.1
retrieving revision 1.10.2.2
diff -u -r1.10.2.1 -r1.10.2.2
--- StatementManagerIF.java 26 Apr 2005 03:41:35 -0000 1.10.2.1
+++ StatementManagerIF.java 4 Jun 2005 14:13:43 -0000 1.10.2.2
@@ -67,8 +67,10 @@
* @param stmt
* @param oid
* @param cld ClassDescriptor for the Object, if <i>null</i> will be
lookup automatic
+ * @param callableStmt Indicate if the specified [EMAIL PROTECTED]
java.sql.PreparedStatement}
+ * is a [EMAIL PROTECTED] java.sql.CallableStatement} supporting stored
procedures.
*/
- void bindSelect(PreparedStatement stmt, Identity oid, ClassDescriptor
cld) throws SQLException;
+ void bindSelect(PreparedStatement stmt, Identity oid, ClassDescriptor
cld, boolean callableStmt) throws SQLException;
/**
* binds the values of the object obj to the statements parameters
*/
@@ -100,7 +102,7 @@
* Return a PreparedStatement for selecting against the given
ClassDescriptor.
*/
PreparedStatement getPreparedStatement(ClassDescriptor cds, String sql,
- boolean scrollable, int
explicitFetchSizeHint)
+ boolean scrollable, int
explicitFetchSizeHint, boolean callableStmt)
throws PersistenceBrokerException;
/**
* return a prepared Select Statement for the given ClassDescriptor
1.10.2.2 +8 -15
db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementsForClassIF.java
Index: StatementsForClassIF.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementsForClassIF.java,v
retrieving revision 1.10.2.1
retrieving revision 1.10.2.2
diff -u -r1.10.2.1 -r1.10.2.2
--- StatementsForClassIF.java 26 Apr 2005 03:41:35 -0000 1.10.2.1
+++ StatementsForClassIF.java 4 Jun 2005 14:13:43 -0000 1.10.2.2
@@ -33,50 +33,43 @@
public interface StatementsForClassIF
{
-
/**
- * returns the DELETE Statement used for clazz.
+ * Returns the DELETE Statement used for clazz.
* @return java.sql.PreparedStatement
*/
-
PreparedStatement getDeleteStmt(Connection con) throws SQLException;
/**
- * returns a generic unprepared Statement used for clazz.
+ * Returns a generic unprepared Statement used for clazz.
* Never use this method for UPDATE/INSERT/DELETE if you want to use the
batch mode.
* @return java.sql.Statement
*/
-
Statement getGenericStmt(Connection con, boolean scrollable) throws
PersistenceBrokerSQLException;
/**
- * returns the INSERT Statement used for clazz.
+ * Returns the INSERT Statement used for clazz.
* @return java.sql.PreparedStatement
*/
PreparedStatement getInsertStmt(Connection con) throws SQLException;
/**
- * returns a prepared Statement used for clazz.
+ * Returns a prepared Statement used for clazz.
* @return java.sql.Statement
*/
-
PreparedStatement getPreparedStmt(Connection con, String sql,
- boolean scrollable, int
explicitFetchSizeHint)
+ boolean scrollable, int
explicitFetchSizeHint, boolean callableStmt)
throws PersistenceBrokerSQLException;
/**
- * returns the SELECT Statement used for clazz.
+ * Returns the SELECT Statement used for clazz.
* @return java.sql.PreparedStatement
*/
-
PreparedStatement getSelectByPKStmt(Connection con) throws SQLException;
/**
- * returns the UPDATE Statement used for clazz.
+ * Returns the UPDATE Statement used for clazz.
* @return java.sql.PreparedStatement
*/
-
PreparedStatement getUpdateStmt(Connection con) throws SQLException;
-
}
1.22.2.5 +3 -9
db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementsForClassImpl.java
Index: StatementsForClassImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/StatementsForClassImpl.java,v
retrieving revision 1.22.2.4
retrieving revision 1.22.2.5
diff -u -r1.22.2.4 -r1.22.2.5
--- StatementsForClassImpl.java 7 May 2005 16:43:05 -0000 1.22.2.4
+++ StatementsForClassImpl.java 4 Jun 2005 14:13:43 -0000 1.22.2.5
@@ -43,11 +43,8 @@
*/
public class StatementsForClassImpl implements StatementsForClassIF
{
-
private Logger log =
LoggerFactory.getLogger(StatementsForClassImpl.class);
- private static final String CALL = "{ ?= call";
-
/**
* sets the escape processing mode
*/
@@ -174,17 +171,14 @@
}
public PreparedStatement getPreparedStmt(Connection con, String sql,
- boolean scrollable, int
explicitFetchSizeHint)
+ boolean scrollable, int
explicitFetchSizeHint, boolean callableStmt)
throws PersistenceBrokerSQLException
{
PreparedStatement stmt = null;
try
{
- // TODO: Vadim Gritsenko FIXME: Improve check for stored
procedure call syntax
- final boolean createPreparedStatement;
- createPreparedStatement = !sql.toLowerCase().startsWith(CALL);
stmt = prepareStatement(con, sql, scrollable,
- createPreparedStatement, explicitFetchSizeHint);
+ !callableStmt, explicitFetchSizeHint);
}
catch (SQLException ex)
{
No revision
No revision
1.24.2.3 +9 -8
db-ojb/src/java/org/apache/ojb/broker/platforms/Platform.java
Index: Platform.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/platforms/Platform.java,v
retrieving revision 1.24.2.2
retrieving revision 1.24.2.3
diff -u -r1.24.2.2 -r1.24.2.3
--- Platform.java 26 Apr 2005 03:41:36 -0000 1.24.2.2
+++ Platform.java 4 Jun 2005 14:13:43 -0000 1.24.2.3
@@ -230,13 +230,14 @@
*/
String getEscapeClause(LikeCriteria aCriteria);
- /**
- * Determines whether statement is [EMAIL PROTECTED] CallableStatement}
or not.
- *
- * @param stmt the statement
- * @return true if statement is [EMAIL PROTECTED] CallableStatement}.
- */
- boolean isCallableStatement(PreparedStatement stmt);
+// arminw: Check is not necessary any longer
+// /**
+// * Determines whether statement is [EMAIL PROTECTED]
CallableStatement} or not.
+// *
+// * @param stmt the statement
+// * @return true if statement is [EMAIL PROTECTED] CallableStatement}.
+// */
+// boolean isCallableStatement(PreparedStatement stmt);
/**
* Registers call argument at <code>position</code> as returning
1.7.2.2 +11 -10
db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java
Index: PlatformHsqldbImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java,v
retrieving revision 1.7.2.1
retrieving revision 1.7.2.2
diff -u -r1.7.2.1 -r1.7.2.2
--- PlatformHsqldbImpl.java 6 Apr 2005 13:29:33 -0000 1.7.2.1
+++ PlatformHsqldbImpl.java 4 Jun 2005 14:13:43 -0000 1.7.2.2
@@ -65,14 +65,15 @@
return true;
}
- /**
- * HSQLDB does not implement CallableStatement.
- *
- * @see
org.apache.ojb.broker.platforms.Platform#isCallableStatement(java.sql.PreparedStatement)
- */
- public boolean isCallableStatement(PreparedStatement stmt)
- {
- return false;
- }
+// arminw: Check is not necessary any longer
+// /**
+// * HSQLDB does not implement CallableStatement.
+// *
+// * @see
org.apache.ojb.broker.platforms.Platform#isCallableStatement(java.sql.PreparedStatement)
+// */
+// public boolean isCallableStatement(PreparedStatement stmt)
+// {
+// return false;
+// }
}
1.10.2.1 +40 -1
db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformSapdbImpl.java
Index: PlatformSapdbImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformSapdbImpl.java,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -r1.10 -r1.10.2.1
--- PlatformSapdbImpl.java 4 Apr 2004 23:53:35 -0000 1.10
+++ PlatformSapdbImpl.java 4 Jun 2005 14:13:43 -0000 1.10.2.1
@@ -27,6 +27,45 @@
*/
public class PlatformSapdbImpl extends PlatformDefaultImpl
{
+// arminw: Check is not necessary any longer
+// final String msgCallableStatement = "Can't check maxDB/sapDB driver
for CallableStatement, will return false";
+// static final String SAP_FIELD_NAME_1 = "parseinfo";
+// static final String SAP_FIELD_NAME_2 = "isDBProc";
+//
+// public boolean isCallableStatement(PreparedStatement stmt)
+// {
+// if(super.isCallableStatement(stmt))
+// {
+// /*
+// arminw: TODO: this is a really bad hook into the maxDB-driver
+// to detect CallableStatement. It's based on two non-public
driver-class fields!!
+// Thus we can't guarantee that it will work with next/older
driver version (7.6.00.00.3360).
+// If a security manager is used this hook could cause problems.
+// Recommend to do a redesign of StatementManager interface to
avoid this check
+// on Platform class.
+// */
+// try
+// {
+// Field fld =
stmt.getClass().getDeclaredField(SAP_FIELD_NAME_1);
+// fld.setAccessible(true);
+// Object parseInfo = fld.get(stmt);
+// fld =
parseInfo.getClass().getDeclaredField(SAP_FIELD_NAME_2);
+// fld.setAccessible(true);
+// Boolean result = (Boolean) fld.get(parseInfo);
+// return result.booleanValue();
+// }
+// catch(Exception e)
+// {
+// if(log.isEnabledFor(Logger.WARN))
log.warn(msgCallableStatement, e);
+// return false;
+// }
+// }
+// else
+// {
+// return false;
+// }
+// }
+
public void setObjectForStatement(
PreparedStatement ps,
int index,
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]