You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by da...@apache.org on 2008/10/10 01:53:04 UTC
svn commit: r703295 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/sql/ engine/org/apache/derby/iapi/sql/conn/
engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/impl/sql/
engine/org/apache/derby/impl/sql/conn/ engine/org/apache/d...
Author: dag
Date: Thu Oct 9 16:53:03 2008
New Revision: 703295
URL: http://svn.apache.org/viewvc?rev=703295&view=rev
Log:
DERBY-3897 SQLSessionContext not correctly initialized in some non-method call nested contexts
Patch derby-3897-3, which sets up the SQL session context correctly
also for substatements. See javadoc for
LanguageConnectionContext#setupSubStatementSessionContext for an
enumeration of these cases. Also adds test cases for this.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedStatement.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesConferredPrivilegesTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java Thu Oct 9 16:53:03 2008
@@ -590,26 +590,33 @@
/**
- * Return the current SQL session context for all immediately
- * nested connections stemming from the call or function
- * invocation of the statement corresponding to this activation.
+ * Get the current SQL session context if in a nested connection of a
+ * stored routine or in a substatement.
*/
- public SQLSessionContext getNestedSQLSessionContext();
+ public SQLSessionContext getSQLSessionContextForChildren();
/**
- * This activation is created in a dynamic call context, remember
- * its caller's activation.
- *
- * @param a The caller's activation
+ * Set up and return the current SQL session context for all immediately
+ * nested connections stemming from the call or function invocation of the
+ * statement corresponding to this activation (push=true) or for a
+ * substatement, which shares the parents statement's session context
+ * (push=false).
+ * @param push true if used to push a new connection context
+ */
+ public SQLSessionContext setupSQLSessionContextForChildren(boolean push);
+
+ /**
+ * This activation is created in a dynamic call context or a substatement
+ * execution context, chain its parent statements activation..
*/
- public void setCallActivation(Activation a);
+ public void setParentActivation(Activation a);
/**
- * This activation is created in a dynamic call context, get its
- * caller's activation.
+ * This activation is created in a dynamic call context, or substatement
+ * execution context; get its caller's or superstatement's activation.
*
* @return The caller's activation
*/
- public Activation getCallActivation();
+ public Activation getParentActivation();
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java Thu Oct 9 16:53:03 2008
@@ -93,7 +93,8 @@
Activation getActivation(LanguageConnectionContext lcc, boolean scrollable) throws StandardException;
/**
- * Execute the PreparedStatement and return results.
+ * Execute the PreparedStatement and return results, used for top level
+ * statements (not substatements) in a connection.
*<p>
* There is no executeQuery() or
* executeUpdate(); a method is provided in
@@ -101,9 +102,6 @@
*
* @param activation The activation containing all the local state
* to execute the plan.
- * @param rollbackParentContext True if 1) the statement context is
- * NOT a top-level context, AND 2) in the event of a statement-level
- * exception, the parent context needs to be rolled back, too.
* @param timeoutMillis timeout value in milliseconds.
*
* @return A ResultSet for a statement. A ResultSet represents
@@ -114,17 +112,53 @@
* @exception StandardException Thrown on failure
*/
ResultSet execute(Activation activation,
- boolean rollbackParentContext,
long timeoutMillis)
throws StandardException;
/**
- Simple form of execute(). Creates a new single use activation and executes it,
- but also passes rollbackParentContext parameter (see above).
- */
- ResultSet execute(LanguageConnectionContext lcc,
- boolean rollbackParentContext,
- long timeoutMillis)
+ * Execute a statement as part of another statement (ithout a nested
+ * connection) and return results.
+ * <p>
+ * There is no executeQuery() or
+ * executeUpdate(); a method is provided in
+ * ResultSet to tell whether to expect rows to be returned.
+ *
+ * @param parent The activation of the superstatement
+ * @param activation The activation containing all the local state
+ * to execute the plan for substatement
+ * @param rollbackParentContext True if in the event of a statement-level
+ * exception, the parent context needs to be rolled back, too.
+ * @param timeoutMillis timeout value in milliseconds.
+ *
+ * @return A ResultSet for a statement. A ResultSet represents
+ * the results returned from the statement, if any.
+ * Will return NULL if the plan for the PreparedStatement
+ * has aged out of cache, or the plan is out of date.
+ *
+ * @exception StandardException Thrown on failure
+ */
+ ResultSet executeSubStatement(Activation parent,
+ Activation activation,
+ boolean rollbackParentContext,
+ long timeoutMillis)
+ throws StandardException;
+
+
+ /**
+ * Execute a statement as part of another statement (without a nested
+ * connection) and return results.
+ * <p>
+ * Creates a new single use activation and executes it, but also passes
+ * rollbackParentContext parameter.
+ * @param lcc language connection context
+ * @param rollbackParentContext True if in the event of a statement-level
+ * exception, the parent context needs to be rolled back, too.
+ * @param timeoutMillis timeout value in milliseconds.
+ * @see #executeSubStatement(Activation, Activation, boolean, long)
+ */
+ ResultSet executeSubStatement(LanguageConnectionContext lcc,
+ boolean rollbackParentContext,
+ long timeoutMillis)
throws StandardException;
/**
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java Thu Oct 9 16:53:03 2008
@@ -471,7 +471,7 @@
/**
* Reset any occurence of schemaName as current default schema in
- * the SQLSessionContext stack to the initial default, presumably
+ * the SQLSessionContext stack to the initial default,
* because schemaName is no longer a valid schema.
*
* @param activation current activation
@@ -1137,25 +1137,55 @@
public boolean roleIsSettable(String role) throws StandardException;
/**
- * Create a new SQL session context for the current activation
- * on the basis of the existing SQL session context (logical
- * session context analogue to call stack push, i.e. this happens
- * when a stored procedure or function that can contain SQL is
- * invoked. Called from generated code, see
- * StaticMethodCallNode#generateSetupNestedSessionContext.
- *
+ * Create a new SQL session context for the current activation on the basis
+ * of the existing SQL session context. This happens when a stored
+ * procedure or function that can contain SQL is invoked, cf. SQL 2003
+ * section 4.27.3, since this gives rise to a nested connection.
+ * <p>
+ * Called from generated code, see
+ * {@code StaticMethodCallNode#generateSetupNestedSessionContext}.
+ * <p>
* The new SQL session context is also set in the current statement
* context (of the invocation).
*
* @see org.apache.derby.impl.sql.compile.StaticMethodCallNode#generateSetupNestedSessionContext
* @see StatementContext#getSQLSessionContext
+ * @see #setupSubStatementSessionContext
*
* @param a activation of the statement which performs the call.
*/
public void setupNestedSessionContext(Activation a);
/**
- * Create a fresh SQLSessionContext
+ * Get the value of top level session context of the top level connection.
+ */
+ public SQLSessionContext getTopLevelSQLSessionContext();
+
+ /**
+ * Used when a statement as part of its operation executes an other
+ * statement. In contrast to setupNestedSessionContext, the activation (for
+ * the substatement) just inherits the current session context from the
+ * parent statements activation, it does <b>not</b> push a new copy on the
+ * stack of session contexts.
+ *
+ * Currently, this is used in the following situations:
+ * <ul>
+ * <li>With {@code ALTER TABLE} adding a column which has a default
+ * values, the default value for all the existing rows is added
+ * using an {@code UPDATE} substatement.
+ * <li>With {@code ALTER TABLE} adding a a check constraint, we will use
+ * a substatement {@code SELECT} to check if all rows satisfy the
+ * constraint.
+ * <li>{@code ResultSet.insertRow}, {@code updateRow}
+ * and {@code deleteRow}.
+ * <li>During trigger body execution.
+ * </ul>
+ * @see #setupNestedSessionContext
+ */
+ public void setupSubStatementSessionContext(Activation a);
+
+ /**
+ * Create a fresh SQLSessionContext for this connection.
* @return new SQLSessionContext
*/
public SQLSessionContext createSQLSessionContext();
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java Thu Oct 9 16:53:03 2008
@@ -3627,7 +3627,7 @@
// Don't see any timeout when inserting rows (use 0)
//execute the insert
org.apache.derby.iapi.sql.ResultSet rs =
- ps.execute(act, true, 0L);
+ ps.executeSubStatement(activation, act, true, 0L);
act.close();
lcc.popStatementContext(statementContext, null);
@@ -3702,7 +3702,8 @@
}
// Don't set any timeout when updating rows (use 0)
// Execute the update where current of sql.
- org.apache.derby.iapi.sql.ResultSet rs = ps.execute(act, true, 0L);
+ org.apache.derby.iapi.sql.ResultSet rs =
+ ps.executeSubStatement(activation, act, true, 0L);
SQLWarning w = act.getWarnings();
if (w != null) {
addWarning(w);
@@ -3767,7 +3768,7 @@
// Don't set any timeout when deleting rows (use 0)
//execute delete where current of sql
org.apache.derby.iapi.sql.ResultSet rs =
- ps.execute(act, true, 0L);
+ ps.executeSubStatement(activation, act, true, 0L);
SQLWarning w = act.getWarnings();
if (w != null) {
addWarning(w);
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedStatement.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedStatement.java Thu Oct 9 16:53:03 2008
@@ -1232,9 +1232,7 @@
//and clear existing result sets in case this has been cached
a.reset();
a.setMaxRows(maxRows);
- ResultSet resultsToWrap = ps.execute(a,
- false,
- timeoutMillis);
+ ResultSet resultsToWrap = ps.execute(a, timeoutMillis);
addWarning(a.getWarnings());
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java Thu Oct 9 16:53:03 2008
@@ -97,9 +97,9 @@
*
*/
-final class GenericActivationHolder implements Activation
+final public class GenericActivationHolder implements Activation
{
- BaseActivation ac;
+ public BaseActivation ac;
ExecPreparedStatement ps;
GeneratedClass gc;
DataTypeDescriptor[] paramTypes;
@@ -580,16 +580,20 @@
return ac.getTargetVTI();
}
- public SQLSessionContext getNestedSQLSessionContext() {
- return ac.getNestedSQLSessionContext();
+ public SQLSessionContext getSQLSessionContextForChildren() {
+ return ac.getSQLSessionContextForChildren();
}
- public void setCallActivation(Activation a) {
- ac.setCallActivation(a);
+ public SQLSessionContext setupSQLSessionContextForChildren(boolean push) {
+ return ac.setupSQLSessionContextForChildren(push);
+ }
+
+ public void setParentActivation(Activation a) {
+ ac.setParentActivation(a);
}
- public Activation getCallActivation() {
- return ac.getCallActivation();
+ public Activation getParentActivation() {
+ return ac.getParentActivation();
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java Thu Oct 9 16:53:03 2008
@@ -240,31 +240,64 @@
// deadlock.
lcc.closeUnusedActivations();
- Activation callingAct = null;
+ Activation parentAct = null;
StatementContext stmctx = lcc.getStatementContext();
if (stmctx != null) {
- // if not null, callingAct represents the activation of
- // a calling statement and this activation corresponds to
- // a statement inside a stored procedure or function
- callingAct = stmctx.getActivation();
+ // If not null, parentAct represents one of 1) the activation of a
+ // calling statement and this activation corresponds to a statement
+ // inside a stored procedure or function, and 2) the activation of
+ // a statement that performs a substatement, e.g. trigger body
+ // execution.
+ parentAct = stmctx.getActivation();
}
- ac.setCallActivation(callingAct);
+ ac.setParentActivation(parentAct);
return ac;
}
- public ResultSet execute(LanguageConnectionContext lcc,
- boolean rollbackParentContext,
- long timeoutMillis)
+ /**
+ * @see PreparedStatement#executeSubStatement(LanguageConnectionContext, boolean, long)
+ */
+ public ResultSet executeSubStatement(LanguageConnectionContext lcc,
+ boolean rollbackParentContext,
+ long timeoutMillis)
throws StandardException
{
+ Activation parent = lcc.getLastActivation();
Activation a = getActivation(lcc, false);
a.setSingleExecution();
- return execute(a, rollbackParentContext, timeoutMillis);
+ lcc.setupSubStatementSessionContext(parent);
+ return executeStmt(a, rollbackParentContext, timeoutMillis);
+ }
+
+ /**
+ * @see PreparedStatement#executeSubStatement(Activation, Activation, boolean, long)
+ */
+ public ResultSet executeSubStatement(Activation parent,
+ Activation activation,
+ boolean rollbackParentContext,
+ long timeoutMillis)
+ throws StandardException
+ {
+ parent.getLanguageConnectionContext().
+ setupSubStatementSessionContext(parent);
+ return executeStmt(activation, rollbackParentContext, timeoutMillis);
}
+
+ /**
+ * @see PreparedStatement#execute
+ */
+ public ResultSet execute(Activation activation,
+ long timeoutMillis)
+ throws StandardException
+ {
+ return executeStmt(activation, false, timeoutMillis);
+ }
+
+
/**
* The guts of execution.
*
@@ -277,10 +310,9 @@
*
* @exception StandardException thrown on error
*/
-
- public ResultSet execute(Activation activation,
- boolean rollbackParentContext,
- long timeoutMillis)
+ private ResultSet executeStmt(Activation activation,
+ boolean rollbackParentContext,
+ long timeoutMillis)
throws
StandardException
{
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java Thu Oct 9 16:53:03 2008
@@ -1844,8 +1844,7 @@
* @see LanguageConnectionContext#getDefaultSchema(Activation a)
*/
public SchemaDescriptor getDefaultSchema(Activation a) {
- return getCurrentSQLSessionContext(a.getCallActivation()).
- getDefaultSchema();
+ return getCurrentSQLSessionContext(a).getDefaultSchema();
}
/**
@@ -1908,13 +1907,11 @@
public void setDefaultSchema(Activation a, SchemaDescriptor sd)
throws StandardException
{
- Activation caller = a.getCallActivation();
-
if (sd == null) {
sd = getInitialDefaultSchemaDescriptor();
}
- getCurrentSQLSessionContext(caller).setDefaultSchema(sd);
+ getCurrentSQLSessionContext(a).setDefaultSchema(sd);
}
@@ -1925,12 +1922,12 @@
public void resetSchemaUsages(Activation activation, String schemaName)
throws StandardException {
- Activation caller = activation.getCallActivation();
+ Activation parent = activation.getParentActivation();
SchemaDescriptor defaultSchema = getInitialDefaultSchemaDescriptor();
// walk SQL session context chain
- while (caller != null) {
- SQLSessionContext ssc = caller.getNestedSQLSessionContext();
+ while (parent != null) {
+ SQLSessionContext ssc = parent.getSQLSessionContextForChildren();
SchemaDescriptor s = ssc.getDefaultSchema();
if (SanityManager.DEBUG) {
@@ -1940,7 +1937,7 @@
if (schemaName.equals(s.getSchemaName())) {
ssc.setDefaultSchema(defaultSchema);
}
- caller = caller.getCallActivation();
+ parent = parent.getParentActivation();
}
// finally top level
@@ -3265,8 +3262,7 @@
* @see LanguageConnectionContext#setCurrentRole(Activation a, String role)
*/
public void setCurrentRole(Activation a, String role) {
- getCurrentSQLSessionContext(a.getCallActivation()).
- setRole(role);
+ getCurrentSQLSessionContext(a).setRole(role);
}
@@ -3274,8 +3270,7 @@
* @see LanguageConnectionContext#getCurrentRoleId(Activation a)
*/
public String getCurrentRoleId(Activation a) {
- return getCurrentSQLSessionContext(a.getCallActivation()).
- getRole();
+ return getCurrentSQLSessionContext(a).getRole();
}
@@ -3285,8 +3280,7 @@
public String getCurrentRoleIdDelimited(Activation a)
throws StandardException {
- String role = getCurrentSQLSessionContext(a.getCallActivation()).
- getRole();
+ String role = getCurrentSQLSessionContext(a).getRole();
if (role != null) {
beginNestedTransaction(true);
@@ -3335,22 +3329,23 @@
}
/**
- * Return the current SQL session context based on caller
+ * Return the current SQL session context of the activation
*
- * @param caller the activation of the caller, if any, of the
- * current activation
+ * @param activation the activation
*/
- private SQLSessionContext getCurrentSQLSessionContext(Activation caller) {
+ private SQLSessionContext getCurrentSQLSessionContext(Activation activation) {
SQLSessionContext curr;
- if (caller == null ) {
+ Activation parent = activation.getParentActivation();
+
+ if (parent == null ) {
// top level
curr = getTopLevelSQLSessionContext();
} else {
- // inside a nested SQL session context (stored
- // procedure/function), the SQL session context is
- // maintained in the activation of the caller
- curr = caller.getNestedSQLSessionContext();
+ // inside a nested connection (stored procedure/function), or when
+ // executing a substatement the SQL session context is maintained
+ // in the activation of the parent
+ curr = parent.getSQLSessionContextForChildren();
}
return curr;
@@ -3386,7 +3381,12 @@
* @see LanguageConnectionContext#setupNestedSessionContext(Activation a)
*/
public void setupNestedSessionContext(Activation a) {
- SQLSessionContext sc = a.getNestedSQLSessionContext();
+ setupSessionContextMinion(a, true);
+ }
+
+ private void setupSessionContextMinion(Activation a,
+ boolean push) {
+ SQLSessionContext sc = a.setupSQLSessionContextForChildren(push);
// Semantics for roles dictate (SQL 4.34.1.1 and 4.27.3.) that the
// role is initially inherited from the current session
@@ -3402,29 +3402,35 @@
StatementContext stmctx = getStatementContext();
- // Since the statement is an invocation, it will now be
- // associated with the pushed SQLSessionContext (and no longer
- // just share that of its caller (or top). The statement
- // contexts of nested connection statements will inherit sc so
- // the SQL session context is available when nested statements
- // are compiled (and executed, for the most part). However,
- // for dynamic result sets, the relevant statement context
- // (originating result set) is no longer available for
- // execution time references to the SQL session context, so we
- // rely on the activation of the caller for accessing it,
- // cf. e.g. overload variants of
- // getDefaultSchema/setDefaultSchema. If such nested
- // connections themselves turn out to be invocations, they in
- // turn get a new SQLSessionContext associated with them etc.
+ // Since the statement is an invocation (iff push=true), it will now be
+ // associated with the pushed SQLSessionContext (and no longer just
+ // share that of its caller (or top). The statement contexts of nested
+ // connection statements will inherit statement context so the SQL
+ // session context is available through it when nested statements are
+ // compiled (and executed, for the most part). However, for dynamic
+ // result sets, the relevant statement context (originating result set)
+ // is no longer available for execution time references to the SQL
+ // session context, so we rely on the activation of the caller for
+ // accessing it, cf. e.g. overload variants of
+ // getDefaultSchema/setDefaultSchema. If such nested connections
+ // themselves turn out to be invocations, they in turn get a new
+ // SQLSessionContext associated with them etc.
stmctx.setSQLSessionContext(sc);
}
/**
- * Get the value of topLevelSSC, possibly initializing it first.
+ * @see LanguageConnectionContext#setupSubStatementSessionContext(Activation a)
+ */
+ public void setupSubStatementSessionContext(Activation a) {
+ setupSessionContextMinion(a, false);
+ }
+
+
+ /**
* @see GenericLanguageConnectionContext#topLevelSSC
*/
- private SQLSessionContext getTopLevelSQLSessionContext() {
+ public SQLSessionContext getTopLevelSQLSessionContext() {
if (topLevelSSC == null) {
topLevelSSC = new SQLSessionContextImpl(
getInitialDefaultSchemaDescriptor());
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java Thu Oct 9 16:53:03 2008
@@ -3101,7 +3101,7 @@
// This is a substatement; for now, we do not set any timeout
// for it. We might change this behaviour later, by linking
// timeout to its parent statement's timeout settings.
- ResultSet rs = ps.execute(lcc, true, 0L);
+ ResultSet rs = ps.executeSubStatement(lcc, true, 0L);
rs.close();
}
@@ -3122,7 +3122,7 @@
// This is a substatement, for now we do not set any timeout for it
// We might change this later by linking timeout to parent statement
- ResultSet rs = ps.execute(lcc, false, 0L);
+ ResultSet rs = ps.executeSubStatement(lcc, false, 0L);
DataValueDescriptor[] rowArray = rs.getNextRow().getRowArray();
rs.close();
rs.finish();
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java Thu Oct 9 16:53:03 2008
@@ -173,37 +173,31 @@
protected UUID UUIDValue;
/**
- * The 'callActivation' of an activation of a statement executing in
+ * The 'parentActivation' of an activation of a statement executing in
* the root connection is null.
*
- * A non-null 'callActivation' represents the activation of the
- * calling statement.
+ * A non-null 'parentActivation' represents the activation of the calling
+ * statement (if we are in a nested connection of a stored routine), or the
+ * activation of the parent statement (if we are executing a substatement)
*
- * That is, if we are executing an SQL statement ('this'
- * activation) inside a stored procedure or function in a nested
- * connection, then 'callActivation' will be non-null.
- *
- * 'callActivation' is set when this activation is created (@see
+ * 'parentActivation' is set when this activation is created (@see
* GenericPreparedStatement#getActivation) based on the top of the
* dynamic call stack of execution, which is tracked by
* StatementContext. The nested SQL session context is initialized
- * by code generated for the call, after parsameters are evaluated
+ * by code generated for the call, after parameters are evaluated
+ * or just substatement execution starts.
* @see org.apache.derby.impl.sql.compile.StaticMethodCallNode#generateSetupNestedSessionContext
+ * @see org.apache.derby.impl.sql.GenericPreparedStatement#executeSubStatement
*
*/
- private Activation callActivation;
+ private Activation parentActivation;
/**
- * The SQL session context of a call is kept here. Also, @see
- * BaseActivation#callActivation.
-
- * A nested execution maintains its session context,
- * nestedSQLSessionContext, in the activation of the calling
- * statement's activation ('this'). While not inside a stored
- * procedure or function, SQL session state state is held by the
- * LanguageConnectionContext.
+ * The SQL session context to be used inside a nested connection in a
+ * stored routine or in a substatement. In the latter case, it is an alias
+ * to the superstatement's session context.
*/
- private SQLSessionContext nestedSQLSessionContext;
+ private SQLSessionContext sqlSessionContextForChildren;
//Following is the position of the session table names list in savedObjects in compiler context
//This is updated to be the correct value at cursor generate time if the cursor references any session table names.
@@ -1379,37 +1373,64 @@
}
/**
- * Return the current SQL session context for all immediately
- * nested connections stemming from the call or function
- * invocation of the statement corresponding to this activation.
+ * @see org.apache.derby.iapi.sql.Activation#getSQLSessionContextForChildren
+ */
+ public SQLSessionContext getSQLSessionContextForChildren() {
+
+ if (SanityManager.DEBUG) {
+ SanityManager.ASSERT
+ (sqlSessionContextForChildren != null,
+ "Expected sqlSessionContextForChildren to be non-null");
+ }
+
+ return sqlSessionContextForChildren;
+ }
+
+ /**
+ * @see org.apache.derby.iapi.sql.Activation#setupSQLSessionContextForChildren
*/
- public SQLSessionContext getNestedSQLSessionContext() {
+ public SQLSessionContext setupSQLSessionContextForChildren(boolean push) {
- if (nestedSQLSessionContext == null) {
- nestedSQLSessionContext = lcc.createSQLSessionContext();
+ if (push) {
+ // Nested connection, so need to push a new context: SQL 2003,
+ // 4.37.1: "An SQL-session is associated with an
+ // SQL-connection.
+ sqlSessionContextForChildren = lcc.createSQLSessionContext();
+ } else {
+ // Substatement, so use current one
+ if (parentActivation != null) {
+ // The parent statement performing the substatement is
+ // itself inside a nested connection (stored routine)
+ sqlSessionContextForChildren =
+ parentActivation.getSQLSessionContextForChildren();
+ } else {
+ // The parent statement performing the substatement is on
+ // top level
+ sqlSessionContextForChildren =
+ lcc.getTopLevelSQLSessionContext();
+ }
}
- return nestedSQLSessionContext;
+ return sqlSessionContextForChildren;
}
/**
- * This activation is created in a dynamic call context, remember
- * its caller's activation.
+ * This activation is created in a dynamic call context or a substatement
+ * execution context, make note of its parent statements activation (a).
*
- * @param a The caller's activation
+ * @param a The caller's or superstatement's activation
*/
- public void setCallActivation(Activation a) {
- callActivation = a;
+ public void setParentActivation(Activation a) {
+ parentActivation = a;
}
/**
- * This activation is created in a dynamic call context, get its
- * caller's activation.
+ * Get the activation of the calling statement or parent statement.
*
- * @return The caller's activation
+ * @return The parent's activation
*/
- public Activation getCallActivation() {
- return callActivation;
+ public Activation getParentActivation() {
+ return parentActivation;
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java Thu Oct 9 16:53:03 2008
@@ -288,7 +288,7 @@
// This is a substatement; for now, we do not set any timeout
// for it. We might change this behaviour later, by linking
// timeout to its parent statement's timeout settings.
- rs = ps.execute(lcc, false, 0L);
+ rs = ps.executeSubStatement(lcc, false, 0L);
ExecRow row = rs.getNextRow();
if (SanityManager.DEBUG)
{
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java Thu Oct 9 16:53:03 2008
@@ -156,7 +156,8 @@
// This is a substatement; for now, we do not set any timeout
// for it. We might change this behaviour later, by linking
// timeout to its parent statement's timeout settings.
- ResultSet rs = ps.execute(spsActivation, false, 0L);
+ ResultSet rs = ps.executeSubStatement
+ (activation, spsActivation, false, 0L);
if( rs.returnsRows())
{
// Fetch all the data to ensure that functions in the select list or values statement will
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesConferredPrivilegesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesConferredPrivilegesTest.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesConferredPrivilegesTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesConferredPrivilegesTest.java Thu Oct 9 16:53:03 2008
@@ -28,6 +28,7 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
import java.util.ArrayList;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -60,6 +61,7 @@
private final static String CONSTRAINTDROPPED = "01500";
private final static String VIEWDROPPED = "01501";
private final static String TRIGGERDROPPED = "01502";
+ private final static String UNRELIABLE = "42Y39";
private final static String[] users = {"test_dbo", "DonaldDuck"};
@@ -165,6 +167,20 @@
"primary key (c1,c2,c3))");
// We made columns all unique so we can test references
// privilege for all columns.
+ s.execute(
+ "create procedure s1.calledNested()" +
+ " language java parameter style java" +
+ " external name " +
+ "'org.apache.derbyTesting.functionTests.tests.lang." +
+ "RolesConferredPrivilegesTest.calledNested' " +
+ " modifies sql data");
+ s.execute
+ ("create function s1.getCurrentRole() " +
+ "returns varchar(30)" +
+ "language java parameter style java external name " +
+ "'org.apache.derbyTesting.functionTests.tests.lang." +
+ "RolesConferredPrivilegesTest.getCurrentRole' " +
+ " reads sql data");
}
};
@@ -1361,6 +1377,129 @@
/**
+ * Test that DEFAULT CURRENT_ROLE works as expected
+ * See DERBY-3897.
+ */
+ public void testDefaultCurrentRole() throws SQLException {
+ Connection dboConn = getConnection();
+ Statement s = dboConn.createStatement();
+ s.execute("grant h to DonaldDuck");
+
+ Connection c = openUserConnection("DonaldDuck");
+ Statement cStmt = c.createStatement();
+ setRole(c, "h");
+
+ // CREATE TABLE
+ cStmt.executeUpdate
+ ("create table t(role varchar(128) default current_role)");
+ cStmt.executeUpdate("insert into t values default");
+ ResultSet rs = cStmt.executeQuery("select * from t");
+ JDBC.assertSingleValueResultSet(rs, "\"H\"");
+ rs.close();
+ cStmt.executeUpdate("drop table t");
+
+ // ALTER TABLE
+ cStmt.executeUpdate("create table t(i int)");
+ cStmt.executeUpdate("insert into t values 1");
+ cStmt.executeUpdate
+ ("alter table t " +
+ "add column role varchar(10) default current_role");
+ rs = cStmt.executeQuery("select * from t");
+ JDBC.assertFullResultSet(rs, new String[][]{{"1", "\"H\""}});
+ rs.close();
+ cStmt.executeUpdate("drop table t");
+
+ // do the same from within a stored procedure
+ s.execute("grant execute on procedure s1.calledNested to DonaldDuck");
+ cStmt.executeUpdate("call s1.calledNested()");
+ setRole(c, "none");
+
+ cStmt.close();
+ s.execute("revoke h from DonaldDuck");
+ s.execute("revoke execute on procedure s1.calledNested " +
+ "from DonaldDuck restrict");
+ s.close();
+
+ c.close();
+ dboConn.close();
+ }
+
+
+ /**
+ * Test that CURRENT_ROLE works as expected in some miscellaneous contexts.
+ * See DERBY-3897.
+ */
+ public void testCurrentRoleInWeirdContexts() throws SQLException {
+ Connection dboConn = getConnection();
+ Statement s = dboConn.createStatement();
+ setRole(dboConn, "a1");
+ s.execute("create table trackCreds(usr varchar(30), role varchar(30))");
+ s.executeUpdate("create table t(i int)");
+ s.execute("grant insert on t to DonaldDuck");
+ s.execute("grant h to DonaldDuck");
+
+ // From within a trigger body:
+ s.execute("create trigger tr after insert on t " +
+ "insert into trackCreds values (current_user, current_role)");
+
+ Connection c = openUserConnection("DonaldDuck");
+ Statement cStmt = c.createStatement();
+ setRole(c, "h");
+ cStmt.executeUpdate("insert into test_dbo.t values 1");
+
+ ResultSet rs = s.executeQuery("select * from trackCreds");
+ JDBC.assertFullResultSet(rs, new String[][]{{"DONALDDUCK", "\"H\""}});
+ rs.close();
+ setRole(c, "none");
+ cStmt.close();
+
+ // From within a CHECK constraint, that we get an error
+ try {
+ s.execute("create table strange(role varchar(30) " +
+ "check (role = current_role))");
+ fail("current_role inside a check constraint should be denied");
+ } catch (SQLException e) {
+ assertSQLState(UNRELIABLE, e);
+ }
+
+ // From within a function, called from a CHECK constraint
+ // executed as a substatement as part of ALTER TABLE.
+ // In this case, the session context stack contains two elements
+ // referenced from the three activations thus:
+ //
+ // top level "alter table" act. -> top level session context
+ // substatement (check constraint act.) -> top level session context
+ // nested connnection in getCurrentRole,
+ // "values current_role" act. -> pushed session context
+ //
+ // Before DERBY-3897 the call to s1.getCurrentRole would yield null
+ // because the pushed session context for getCurrentRole would inherit
+ // a wrong (newly created) session context from the CHECK constraint
+ // substatement's activation. After DERBY-3897, the substatement
+ // correctly inherits the session context of "alter table"s
+ // activation, so the pushed session context for getCurrentRole will
+ // be correct, too.
+ //
+ s.execute("create table strange(i int)");
+ s.execute("insert into strange values null");
+ s.execute("alter table strange " +
+ "add constraint s check (s1.getCurrentRole() = '\"A1\"')");
+
+ s.execute("revoke h from DonaldDuck");
+ s.execute("revoke insert on t from DonaldDuck");
+ setRole(dboConn, "none");
+ s.execute("drop table trackCreds");
+ s.execute("drop table t");
+ s.execute("drop table strange");
+ s.close();
+
+ c.close();
+ dboConn.close();
+ }
+
+
+
+ /**
* stored function: s1.f1
*/
public static int s1f1() {
@@ -2481,5 +2620,70 @@
fail(b.toString());
}
}
+
+ public static void calledNested()
+ throws SQLException
+ {
+ Connection c = null;
+
+ try {
+ c = DriverManager.getConnection("jdbc:default:connection");
+ Statement cStmt = c.createStatement();
+
+ // CREATE TABLE
+ cStmt.executeUpdate
+ ("create table t(role varchar(128) default current_role)");
+ cStmt.executeUpdate("insert into t values default");
+ ResultSet rs = cStmt.executeQuery("select * from t");
+ JDBC.assertSingleValueResultSet(rs, "\"H\"");
+ rs.close();
+ cStmt.executeUpdate("drop table t");
+
+ // ALTER TABLE
+ cStmt.executeUpdate("create table t(i int)");
+ cStmt.executeUpdate("insert into t values 1");
+ cStmt.executeUpdate
+ ("alter table t " +
+ "add column role varchar(10) default current_role");
+ rs = cStmt.executeQuery("select * from t");
+ JDBC.assertFullResultSet(rs, new String[][]{{"1", "\"H\""}});
+ rs.close();
+ cStmt.executeUpdate("drop table t");
+ cStmt.close();
+ } finally {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+
+
+ public static String getCurrentRole()
+ throws SQLException
+ {
+ Connection c = null;
+
+ try {
+ c = DriverManager.getConnection("jdbc:default:connection");
+ Statement cStmt = c.createStatement();
+
+ ResultSet rs = cStmt.executeQuery("values current_role");
+ rs.next();
+ String result = rs.getString(1);
+ rs.close();
+ cStmt.close();
+ return result;
+ } finally {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java Thu Oct 9 16:53:03 2008
@@ -270,6 +270,13 @@
for (int i= 0; i < variableKeywords.length; i++) {
ps[i].close();
}
+
+ // DERBY-3897: See
+ //
+ // RolesConferredPrivilegesTest#testDefaultCurrentRole and
+ // RolesConferredPrivilegesTest#testCurrentRoleInWeirdContexts
+ //
+ // which are also relevant tests for SQLSessionContext.
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java?rev=703295&r1=703294&r2=703295&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java Thu Oct 9 16:53:03 2008
@@ -764,7 +764,7 @@
/**
* Asserts a ResultSet returns a single row with a single
* column equal to the passed in String value. The value can
- * be null to indicate SQL NULL. The comparision is make
+ * be null to indicate SQL NULL. The comparision is made
* using assertFullResultSet in trimmed string mode.
* As a side effect, this method closes the ResultSet.
*/