From derby-commits-return-9955-apmail-db-derby-commits-archive=db.apache.org@db.apache.org Wed Apr 02 14:36:17 2008 Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 13457 invoked from network); 2 Apr 2008 14:36:17 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 2 Apr 2008 14:36:17 -0000 Received: (qmail 84120 invoked by uid 500); 2 Apr 2008 14:36:17 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 84100 invoked by uid 500); 2 Apr 2008 14:36:16 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 84089 invoked by uid 99); 2 Apr 2008 14:36:16 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Apr 2008 07:36:16 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Apr 2008 14:35:42 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 0AA071A9832; Wed, 2 Apr 2008 07:35:54 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r643920 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/ engine/org/apache/derby/iapi/sql/conn/ engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/impl/sql/ engine/... Date: Wed, 02 Apr 2008 14:35:41 -0000 To: derby-commits@db.apache.org From: dag@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080402143554.0AA071A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dag Date: Wed Apr 2 07:35:37 2008 New Revision: 643920 URL: http://svn.apache.org/viewvc?rev=643920&view=rev Log: DERBY-3327 SQL roles: Implement authorization stack (and SQL session context to hold it) Patch DERBY-3327-4-full-e. See javadoc for SQLSessionContext for more details. This patch also solves DERBY-1331. Added: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java (with props) db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java (with props) db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SQLSessionContextTest.java (with props) 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/conn/LanguageConnectionContext.java db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/StatementContext.java db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/SchemaDescriptor.java db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.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/compile/SpecialFunctionNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.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/conn/GenericStatementContext.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/BasicNoPutResultSetImpl.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropSchemaConstantAction.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetSchemaConstantAction.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -24,6 +24,7 @@ import org.apache.derby.iapi.error.StandardException; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator; import org.apache.derby.iapi.sql.dictionary.TableDescriptor; @@ -586,23 +587,13 @@ */ public int getMaxDynamicResults(); - /** - * Set the current role name of the dynamic call context stemming - * from this activation (which must be a stored - * procedure/function) call. - * - * @param role The name of the current role - */ - public void setNestedCurrentRole(String role); /** - * Get the current role name of the dynamic call context stemming - * from this activation (which must be a stored - * procedure/function) call. - * - * @return The name of the current role + * 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. */ - public String getNestedCurrentRole(); + public SQLSessionContext getNestedSQLSessionContext(); /** * This activation is created in a dynamic call context, remember 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -424,16 +424,32 @@ public String getAuthorizationId(); /** - * Get the current default schema for the connection. + * Get the default schema (used at compile-time when no activation + * is yet available, cf. the activation argument overload version. * - * @return SchemaDescriptor the current schema + * @return SchemaDescriptor the default schema */ public SchemaDescriptor getDefaultSchema(); /** - * Set the current default schema + * Get the default schema (used at execution time). At execution + * time, the current statement context is not always a reliable + * place to find the correct SQL session context, viz. when a + * dynamic result set referencing CURRENT SCHEMA is accessed after + * a called procedure has returned only the activation of the call + * is live and still holds the correct session context. + * @param a current activation + * + * @return SchemaDescriptor the default schema + */ + public SchemaDescriptor getDefaultSchema(Activation a); + + /** + * Set the default schema (at compile-time, see explanations for + * getDefaultSchema overloads). * - * @param sd the new default schema + * @param sd the new default schema. + * If null, then the default schema descriptor is used. * * @exception StandardException thrown on failure */ @@ -441,13 +457,48 @@ throws StandardException; /** - * Get the current schema name + * Set the default schema (at execution time, see explanations for + * getDefaultSchema overloads); This version is used by SET SCHEMA. + * + * @param a current activation + * @param sd the new default schema. + * If null, then the default schema descriptor is used. + * + * @exception StandardException thrown on failure + */ + public void setDefaultSchema(Activation a, SchemaDescriptor sd) + throws StandardException; + + /** + * Reset any occurence of schemaName as current default schema in + * the SQLSessionContext stack to the initial default, presumably + * because schemaName is no longer a valid schema. + * + * @param activation current activation + * @param schemaName the schema name occurences of which is to be reset + * + * @throws StandardException + */ + public void resetSchemaUsages(Activation activation, String schemaName) + throws StandardException; + + /** + * Get the current schema name (at compile-time, see explanations for + * getDefaultSchema overloads). * * @return SchemaDescriptor the current schema */ public String getCurrentSchemaName(); /** + * Get the current schema name (at execution time, see explanations for + * getDefaultSchema overloads); This version is used by CURRENT SCHEMA. + * + * @return SchemaDescriptor the current schema + */ + public String getCurrentSchemaName(Activation a); + + /** * Get the identity column value most recently generated. * * @return the generated identity column value @@ -540,7 +591,7 @@ * @param timeoutMillis Timeout value for this statement, in milliseconds. * Zero means no timeout. * - * @return StatementContext The statement context. + * @return StatementContext The statement context. * */ StatementContext pushStatementContext(boolean isAtomic, boolean isForReadOnly, String stmtText, @@ -1034,22 +1085,6 @@ public void closeUnusedActivations() throws StandardException; /** - * Remember most recent (call stack top) caller's activation when - * invoking a method, see CallStatementResultSet#open. - */ - public void pushCaller(Activation a); - - /** - * Companion of pushCaller. See usage in CallStatementResultSet#open. - */ - public void popCaller(); - - /** - * Get most recent (call stack top) caller's activation - */ - public Activation getCaller(); - - /** * Set the current role * * @param a activation of set role statement @@ -1066,4 +1101,27 @@ */ public String getCurrentRoleId(Activation a); + /** + * 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. + * + * 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 + * + * @param a activation of the statement which performs the call. + */ + public void setupNestedSessionContext(Activation a); + + /** + * Create a fresh SQLSessionContext + * @return new SQLSessionContext + */ + public SQLSessionContext createSQLSessionContext(); } Added: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java?rev=643920&view=auto ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java (added) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java Wed Apr 2 07:35:37 2008 @@ -0,0 +1,91 @@ +/* + + Derby - Class org.apache.derby.iapi.sql.conn.SQLSessionContext + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.iapi.sql.conn; + +import java.lang.String; +import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; + +/** + * An implementation of this interface encapsulates some of the SQL + * session context's state variables, cf. SQL 2003, section 4.37.3, + * notably those which we need to save and restore when entering a + * stored procedure or function (which can contain SQL and thus a + * nested connection), cf. 4.37.3, 4.27.3 and 4.34.1.1.

Presently + * this set contains the following properties:

  • current + * role
  • current schema
+ * + * The standard specifies that the authorization stack be copied onto + * the new SQL session context before it is pushed (and possibly + * modifed) with a new cell for the authorization ids (user, role). In + * our implementation we merge these two stacks for now. Also, the + * authorization id of current user is not represented yet, since it + * can not be modified in a session; Derby can not run routines with + * definer's rights yet. + *

+ * SQL session context is implemented as follows: Statements at root + * connection level use the instance held by the the lcc, nested + * connections maintain instances of SQLSessionContext, held by the + * activation of the calling statement. This forms a logical stack as + * required by the standard. The statement context also holds a + * reference to the current SQLSessionContext. + *

+ * When a dynamic result set references e.g. current role, the value + * retrieved will always be that of the current role when the + * statement is logically executed (inside procedure/function), not + * the current value when the result set is accessed outside the + * stored procedure/function. This works since the nested SQL session + * context is kept by the caller activation, so even though the + * statement context of the call has been popped, we can get at the + * final state of the nested SQL session context since the caller's + * activation is alive as long as dynamic result sets need it). + *

+ * If more than one nested connection is used inside a shared + * procedure, they will share the same nested SQL session + * context. Since the same dynamic call context is involved, this + * seems correct. + * + * @see org.apache.derby.iapi.sql.conn.LanguageConnectionContext#setupNestedSessionContext + */ + +public interface SQLSessionContext { + + /** + * Set the SQL role of this SQL connection context + * The empty string is returned if role is NONE. + */ + public void setRole(String role); + + /** + * Get the SQL role of this SQL connection context + */ + public String getRole(); + + /** + * Set the schema of this SQL connection context + */ + public void setDefaultSchema(SchemaDescriptor sd); + + /** + * Get the schema of this SQL connection context + */ + public SchemaDescriptor getDefaultSchema(); +} Propchange: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/SQLSessionContext.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/StatementContext.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/StatementContext.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/StatementContext.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/StatementContext.java Wed Apr 2 07:35:37 2008 @@ -36,6 +36,7 @@ import org.apache.derby.iapi.types.DataValueFactory; import org.apache.derby.iapi.sql.LanguageFactory; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; /** * StatementContext keeps the context for a statement. @@ -248,5 +249,32 @@ too. */ public void setParentRollback(); + + /** + * Mark this statement context as associated with this activation. + * + * @param a activation + */ + public void setActivation(Activation a); + + /** + * Get activation associated with this statement context, if any. + * Used to link up stack of activations of calls in nested + * connections, see GenericPreparedStatement#getActivation. + */ + public Activation getActivation(); + + + /** + * Get the current SQL session context + */ + public SQLSessionContext getSQLSessionContext(); + + /** + * Set the current SQL session context + * + * @param ctx the SQL session context + */ + public void setSQLSessionContext(SQLSessionContext ctx); } Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/SchemaDescriptor.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/SchemaDescriptor.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/SchemaDescriptor.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/SchemaDescriptor.java Wed Apr 2 07:35:37 2008 @@ -24,6 +24,7 @@ import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; import org.apache.derby.iapi.sql.depend.DependencyManager; import org.apache.derby.iapi.sql.depend.Provider; +import org.apache.derby.iapi.sql.Activation; import org.apache.derby.iapi.store.access.TransactionController; import org.apache.derby.catalog.DependableFinder; import org.apache.derby.iapi.services.io.StoredFormatIds; @@ -394,7 +395,8 @@ * reset through the language connection context. * @throws StandardException Schema could not be dropped. */ - public void drop(LanguageConnectionContext lcc) throws StandardException + public void drop(LanguageConnectionContext lcc, + Activation activation) throws StandardException { DataDictionary dd = getDataDictionary(); DependencyManager dm = dd.getDependencyManager(); @@ -434,11 +436,6 @@ ** LCC is free to set the new default schema to ** some system defined default. */ - SchemaDescriptor currentDefault = lcc.getDefaultSchema(); - if ((currentDefault != null) && - getSchemaName().equals(currentDefault.getSchemaName())) - { - lcc.setDefaultSchema((SchemaDescriptor)null); - } + lcc.resetSchemaUsages(activation, getSchemaName()); } } 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -3612,6 +3612,8 @@ lcc.prepareInternalStatement(insertSQL.toString()); Activation act = ps.getActivation(lcc, false); + statementContext.setActivation(act); + // in this for loop we are assigning values for parameters //in sql constructed earlier VALUES (?, ..) for (int i=1, paramPosition=0; i<=resultDescription.getColumnCount(); i++) { @@ -3691,6 +3693,8 @@ org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(updateWhereCurrentOfSQL.toString()); Activation act = ps.getActivation(lcc, false); + statementContext.setActivation(act); + //in this for loop we are assigning values for parameters in sql constructed earlier with columnname=?,... for (int i=1, paramPosition=0; i<=resultDescription.getColumnCount(); i++) { if (columnGotUpdated[i-1]) //if the column got updated, do following @@ -3757,6 +3761,9 @@ org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(deleteWhereCurrentOfSQL.toString()); // Get activation, so that we can get the warning from it Activation act = ps.getActivation(lcc, false); + + statementContext.setActivation(act); + // Don't set any timeout when deleting rows (use 0) //execute delete where current of sql org.apache.derby.iapi.sql.ResultSet rs = 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -22,6 +22,7 @@ package org.apache.derby.impl.sql; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; import org.apache.derby.iapi.types.DataValueFactory; @@ -564,12 +565,8 @@ return ac.getTargetVTI(); } - public void setNestedCurrentRole(String role) { - ac.setNestedCurrentRole(role); - } - - public String getNestedCurrentRole() { - return ac.getNestedCurrentRole(); + public SQLSessionContext getNestedSQLSessionContext() { + return ac.getNestedSQLSessionContext(); } public void setCallActivation(Activation a) { 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -240,7 +240,17 @@ // deadlock. lcc.closeUnusedActivations(); - ac.setCallActivation(lcc.getCaller()); + Activation callingAct = 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(); + } + + ac.setCallActivation(callingAct); return ac; } @@ -349,6 +359,8 @@ StatementContext statementContext = lccToUse.pushStatementContext( isAtomic, updateMode==CursorNode.READ_ONLY, getSource(), pvs, rollbackParentContext, timeoutMillis); + + statementContext.setActivation(activation); if (needsSavepoint()) { Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java Wed Apr 2 07:35:37 2008 @@ -232,7 +232,9 @@ ClassName.LanguageConnectionContext, 0); int argCount = 0; - if (methodName.equals("getCurrentRoleId")) { + if (methodName.equals("getCurrentRoleId") || + methodName.equals("getCurrentSchemaName")) { + acb.pushThisAsActivation(mb); argCount++; } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java Wed Apr 2 07:35:37 2008 @@ -609,6 +609,35 @@ } /** + * Add code to set up the SQL session context for a stored + * procedure or function which needs a nested SQL session + * context (only needed for those which can contain SQL). + * + * The generated code calls setupNestedSessionContext. + * @see org.apache.derby.iapi.sql.conn.LanguageConnectionContext#setupNestedSessionContext + * + * @param acb activation class builder + * @param mb method builder + */ + private void generateSetupNestedSessionContext(ActivationClassBuilder acb, + MethodBuilder mb) { + + // Generates the following Java code: + // ((Activation)this).getLanguageConnectionContext(). + // setupNestedSessionContext((Activation)this); + + acb.pushThisAsActivation(mb); + mb.callMethod(VMOpcode.INVOKEINTERFACE, null, + "getLanguageConnectionContext", + ClassName.LanguageConnectionContext, 0); + acb.pushThisAsActivation(mb); + mb.callMethod(VMOpcode.INVOKEINTERFACE, null, + "setupNestedSessionContext", + "void", 1); + } + + + /** Push extra code to generate the casts within the arrays for the parameters passed as arrays. */ @@ -868,6 +897,13 @@ if (isSystemCode) { mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSystemCode", "void", 0); + } + + // If no SQL, there is no need to setup a nested session + // context. + if (sqlAllowed != RoutineAliasInfo.NO_SQL) { + generateSetupNestedSessionContext((ActivationClassBuilder) acb, + mb); } // for a function we need to fetch the current SQL control 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -47,10 +47,10 @@ import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory; import org.apache.derby.iapi.sql.conn.StatementContext; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptorList; import org.apache.derby.iapi.sql.dictionary.DataDictionary; -import org.apache.derby.iapi.sql.dictionary.RoleDescriptor; import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; import org.apache.derby.iapi.sql.dictionary.TableDescriptor; import org.apache.derby.iapi.types.DataValueFactory; @@ -73,7 +73,6 @@ import org.apache.derby.iapi.store.access.TransactionController; import org.apache.derby.iapi.store.access.XATransactionController; import org.apache.derby.iapi.util.IdUtil; -import org.apache.derby.iapi.util.StringUtil; import org.apache.derby.catalog.UUID; import org.apache.derby.iapi.sql.execute.RunTimeStatistics; @@ -163,18 +162,6 @@ */ private int queryNestingDepth; - /** - * 'callers' keeps track of which, if any, stored procedure - * activations are active. This helps implement the "authorization - * stack" of SQL 2003, vol 2, section 4.34.1.1 and 4.27.3. - * - * For the top level, the current role is kept here, - * cf. 'currentRole'. For dynamic call contexts, the current role - * is kept in the activation of the calling statement, - * cf. 'getCurrentRoleId'. - */ - private ArrayList callers = new ArrayList(); // used as a stack only - protected DataValueFactory dataFactory; protected LanguageFactory langFactory; protected TypeCompilerFactory tcf; @@ -197,8 +184,22 @@ protected Authorizer authorizer; protected String userName = null; //The name the user connects with. //May still be quoted. - protected String currentRole; - protected SchemaDescriptor sd; + /** + * The top SQL session context stack frame (SQL 2003, section + * 4.37.3), is kept in topLevelSSC. For nested session contexts, + * the SQL session context is held by the activation of the + * calling statement, cf. setupNestedSessionContext and it is + * accessible through the current statement context + * (compile-time), or via the current activation (execution-time). + * @see GenericLanguageConnectionContext#getTopLevelSQLSessionContext + */ + private SQLSessionContext topLevelSSC; + + /** + * Used to hold the computed value of the initial default schema, + * cf logic in initDefaultSchemaDescriptor. + */ + private SchemaDescriptor cachedInitialDefaultSchemaDescr = null; // RESOLVE - How do we want to set the default. private int defaultIsolationLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL; @@ -345,6 +346,13 @@ setDefaultSchema(initDefaultSchemaDescriptor()); } + /** + * Compute the initial default schema and set + * cachedInitialDefaultSchemaDescr accordingly. + * + * @return computed initial default schema value for this session + * @throws StandardException + */ protected SchemaDescriptor initDefaultSchemaDescriptor() throws StandardException { /* @@ -355,18 +363,37 @@ ** user. ** - Else Set the default schema to APP. */ - // SchemaDescriptor sd; + if (cachedInitialDefaultSchemaDescr == null) { + DataDictionary dd = getDataDictionary(); + String authorizationId = getAuthorizationId(); + SchemaDescriptor sd = + dd.getSchemaDescriptor( + authorizationId, getTransactionCompile(), false); - DataDictionary dd = getDataDictionary(); - String authorizationId = getAuthorizationId(); - - if ( (sd = dd.getSchemaDescriptor(authorizationId, getTransactionCompile(), false)) == null ) - { - sd = new SchemaDescriptor(dd, authorizationId, authorizationId, (UUID) null, false); + if (sd == null) { + sd = new SchemaDescriptor( + dd, authorizationId, authorizationId, (UUID) null, false); + } + + cachedInitialDefaultSchemaDescr = sd; } - return sd; + return cachedInitialDefaultSchemaDescr; } + /** + * Get the computed value for the initial default schema. + * @return the schema descriptor of the computed initial default schema + */ + private SchemaDescriptor getInitialDefaultSchemaDescriptor() { + if (SanityManager.DEBUG) { + SanityManager.ASSERT(cachedInitialDefaultSchemaDescr != null, + "cachedInitialDefaultSchemaDescr is null!"); + } + + return cachedInitialDefaultSchemaDescr; + } + + // // LanguageConnectionContext interface // @@ -774,7 +801,8 @@ public PreparedStatement prepareInternalStatement(String sqlText) throws StandardException { - return connFactory.getStatement(sd, sqlText, true).prepare(this); + return connFactory. + getStatement(getDefaultSchema(), sqlText, true).prepare(this); } /** @@ -1780,45 +1808,118 @@ return authorizer.getAuthorizationId(); } - /** - * Get the default schema - * - * @return SchemaDescriptor the default schema + * @see LanguageConnectionContext#getDefaultSchema */ public SchemaDescriptor getDefaultSchema() { - return sd; + return getCurrentSQLSessionContext().getDefaultSchema(); } + /** - * Get the current schema name - * - * @return current schema name + * @see LanguageConnectionContext#getDefaultSchema(Activation a) + */ + public SchemaDescriptor getDefaultSchema(Activation a) { + return getCurrentSQLSessionContext(a.getCallActivation()). + getDefaultSchema(); + } + + /** + * @see LanguageConnectionContext#getCurrentSchemaName() */ public String getCurrentSchemaName() { - if( null == sd) - return null; - return sd.getSchemaName(); + // getCurrentSchemaName with no arg is used even + // at run-time but only in places(*) where the statement context + // can be relied on, AFAICT. + // + // (*) SpaceTable#getConglomInfo, + // SystemProcedures#{INSTALL|REPLACE|REMOVE}_JAR + + SchemaDescriptor s = getDefaultSchema(); + if( null == s) + return null; + return s.getSchemaName(); } + /** - * Set the default schema -- used by SET SCHEMA. - * - * @param sd the new default schema. - * If null, then the default schema descriptor is used. - * - * @exception StandardException thrown on failure + * @see LanguageConnectionContext#getCurrentSchemaName(Activation a) + */ + public String getCurrentSchemaName(Activation a) + { + SchemaDescriptor s = getDefaultSchema(a); + if( null == s) + return null; + return s.getSchemaName(); + } + + /** + * @see LanguageConnectionContext#setDefaultSchema(SchemaDescriptor sd) */ public void setDefaultSchema(SchemaDescriptor sd) throws StandardException { - if (sd == null) - { - sd = initDefaultSchemaDescriptor(); + if (sd == null) { + sd = getInitialDefaultSchemaDescriptor(); + } + + getCurrentSQLSessionContext().setDefaultSchema(sd); + } + + /** + * @see LanguageConnectionContext#setDefaultSchema(Activation a, + * SchemaDescriptor sd) + */ + public void setDefaultSchema(Activation a, SchemaDescriptor sd) + throws StandardException + { + Activation caller = a.getCallActivation(); + + if (sd == null) { + sd = getInitialDefaultSchemaDescriptor(); + } + + getCurrentSQLSessionContext(caller).setDefaultSchema(sd); + } + + + /** + * @see LanguageConnectionContext#resetSchemaUsages(Activation activation, + * String schemaName) + */ + public void resetSchemaUsages(Activation activation, String schemaName) + throws StandardException { + + Activation caller = activation.getCallActivation(); + SchemaDescriptor defaultSchema = getInitialDefaultSchemaDescriptor(); + + // walk SQL session context chain + while (caller != null) { + SQLSessionContext ssc = caller.getNestedSQLSessionContext(); + SchemaDescriptor s = ssc.getDefaultSchema(); + + if (SanityManager.DEBUG) { + SanityManager.ASSERT(s != null, "s should not be empty here"); + } + + if (schemaName.equals(s.getSchemaName())) { + ssc.setDefaultSchema(defaultSchema); + } + caller = caller.getCallActivation(); + } + + // finally top level + SQLSessionContext top = getTopLevelSQLSessionContext(); + SchemaDescriptor sd = top.getDefaultSchema(); + + if (SanityManager.DEBUG) { + SanityManager.ASSERT(sd != null, "sd should not be empty here"); + } + + if (schemaName.equals(sd.getSchemaName())) { + top.setDefaultSchema(defaultSchema); } - this.sd = sd; - } /** @@ -1968,6 +2069,10 @@ /** * Push a StatementContext on the context stack. * + * Inherit SQL session state a priori (statementContext will get + * its own SQL session state if this statement executes a call, + * cf. setupNestedSessionContext. + * @param isAtomic whether this statement is atomic or not * @param isForReadOnly whether this statement is for a read only resultset * @param stmtText the text of the statement. Needed for any language @@ -2000,9 +2105,12 @@ ** If we haven't allocated any statement contexts yet, allocate ** the outermost stmt context now and push it. */ + if (statementContext == null) { statementContext = statementContexts[0] = new GenericStatementContext(this); + statementContext. + setSQLSessionContext(getTopLevelSQLSessionContext()); } else if (statementDepth > 0) { @@ -2028,11 +2136,17 @@ statementContext = new GenericStatementContext(this); } + statementContext.setSQLSessionContext( + parentStatementContext.getSQLSessionContext()); + inTrigger = parentStatementContext.inTrigger() || (outermostTrigger == parentStatementDepth); parentIsAtomic = parentStatementContext.isAtomic(); statementContext.setSQLAllowed(parentStatementContext.getSQLAllowed(), false); if (parentStatementContext.getSystemCode()) statementContext.setSystemCode(); + } else { + statementContext. + setSQLSessionContext(getTopLevelSQLSessionContext()); } incrementStatementDepth(); @@ -3112,74 +3226,130 @@ return sb; } + /** - * Remember most recent (call stack top) caller's activation when - * invoking a method, see CallStatementResultSet#open. + * @see LanguageConnectionContext#setCurrentRole(Activation a, String role) */ - public void pushCaller(Activation a) { - callers.add(a); + public void setCurrentRole(Activation a, String role) { + getCurrentSQLSessionContext(a.getCallActivation()). + setRole(role); } + /** - * Companion of pushCaller. See usage in CallStatementResultSet#open. + * @see LanguageConnectionContext#getCurrentRoleId(Activation a) */ - public void popCaller() { - callers.remove(callers.size() - 1); + public String getCurrentRoleId(Activation a) { + return getCurrentSQLSessionContext(a.getCallActivation()). + getRole(); } /** - * Get most recent (call stack top) caller's activation - * or null, if not in a call context. + * Return the current SQL session context based on caller + * + * @param caller the activation of the caller, if any, of the + * current activation */ - public Activation getCaller() { - if (callers.isEmpty()) { - return null; + private SQLSessionContext getCurrentSQLSessionContext(Activation caller) { + SQLSessionContext curr; + + if (caller == null ) { + // top level + curr = getTopLevelSQLSessionContext(); } else { - return (Activation)callers.get(callers.size() - 1); + // inside a nested SQL session context (stored + // procedure/function), the SQL session context is + // maintained in the activation of the caller + curr = caller.getNestedSQLSessionContext(); } + + return curr; } /** - * Set the current role - * - * @param a activation of set role statement - * @param role the id of the role to be set to current + * Return the current SQL session context based on statement context */ - public void setCurrentRole(Activation a, String role) { - Activation caller = a.getCallActivation(); - - if (caller != null ) { - //inside a stored procedure context - caller.setNestedCurrentRole(role); + private SQLSessionContext getCurrentSQLSessionContext() { + StatementContext ctx = getStatementContext(); + SQLSessionContext curr; + + if (ctx == null || !ctx.inUse()) { + curr = getTopLevelSQLSessionContext(); } else { - // top level - this.currentRole = role; + // We are inside a nested connection in a procedure of + // function. + curr = ctx.getSQLSessionContext(); + + if (SanityManager.DEBUG) { + SanityManager.ASSERT( + curr != null, + "SQL session context should never be empty here"); + } } + + return curr; } /** - * Get the current role authorization identifier of the dynamic - * call context associated with this activation. - * - * @param a activation of statement needing current role - * @return String the role id + * @see LanguageConnectionContext#setupNestedSessionContext(Activation a) */ - public String getCurrentRoleId(Activation a) { - Activation caller = a.getCallActivation(); + public void setupNestedSessionContext(Activation a) { + SQLSessionContext sc = a.getNestedSQLSessionContext(); - if (caller != null ) { - // Want current role of stored procedure context - // Note that it may have returned at this point, but the - // activation still keeps track on what the current role - // was when we returned. - return caller.getNestedCurrentRole(); - } else { - // Top level current role, no stored procedure call - // context. - return currentRole; + // Semantics for roles dictate (SQL 4.34.1.1 and 4.27.3.) that the + // role is initially inherited from the current session + // context. (Since we always run with INVOKER security + // characteristic. Derby can't yet run with DEFINER's rights). + // + sc.setRole(getCurrentRoleId(a)); + + // Inherit current default schema. The initial value of the + // default schema is implementation defined. In Derby we + // inherit it when we invoke stored procedures and functions. + sc.setDefaultSchema(getDefaultSchema(a)); + + 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. + stmctx.setSQLSessionContext(sc); + } + + + /** + * Get the value of topLevelSSC, possibly initializing it first. + * @see GenericLanguageConnectionContext#topLevelSSC + */ + private SQLSessionContext getTopLevelSQLSessionContext() { + if (topLevelSSC == null) { + topLevelSSC = new SQLSessionContextImpl( + getInitialDefaultSchemaDescriptor()); } + return topLevelSSC; } + + + /** + * @see LanguageConnectionContext#createSQLSessionContext + */ + public SQLSessionContext createSQLSessionContext() { + return new SQLSessionContextImpl( + getInitialDefaultSchemaDescriptor()); + } + } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericStatementContext.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericStatementContext.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericStatementContext.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericStatementContext.java Wed Apr 2 07:35:37 2008 @@ -33,12 +33,14 @@ import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; import org.apache.derby.iapi.sql.conn.StatementContext; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; import org.apache.derby.iapi.sql.depend.Dependency; import org.apache.derby.iapi.sql.depend.DependencyManager; import org.apache.derby.iapi.sql.execute.NoPutResultSet; +import org.apache.derby.iapi.sql.Activation; import org.apache.derby.iapi.sql.ResultSet; import org.apache.derby.iapi.sql.ParameterValueSet; @@ -96,6 +98,16 @@ */ private short sqlAllowed = -1; + /** + * The activation associated with this context, or null + */ + private Activation activation; + + /** + * The SQLSessionContext associated with a statement context. + */ + private SQLSessionContext sqlSessionContext; + /* constructor @param tc transaction @@ -228,7 +240,9 @@ cancelTask = null; } cancellationFlag = false; - } + activation = null; + sqlSessionContext = null; + } /** * @see StatementContext#setSavePoint @@ -743,5 +757,33 @@ } return sb; + } + + /** + * @see StatementContext#setActivation(Activation a) + */ + public void setActivation(Activation a) { + activation = a; + } + + /** + * @see StatementContext#getActivation + */ + public Activation getActivation() { + return activation; + } + + /** + * @see StatementContext#getSQLSessionContext + */ + public SQLSessionContext getSQLSessionContext() { + return sqlSessionContext; + } + + /** + * @see StatementContext#setSQLSessionContext(SQLSessionContext ctx) + */ + public void setSQLSessionContext(SQLSessionContext ctx) { + sqlSessionContext = ctx; } } Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java?rev=643920&view=auto ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java (added) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java Wed Apr 2 07:35:37 2008 @@ -0,0 +1,53 @@ +/* + + Derby - Class org.apache.derby.impl.sql.conn.SQLSessionContextImpl + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.impl.sql.conn; + +import java.lang.String; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; +import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; + +public class SQLSessionContextImpl implements SQLSessionContext { + + private String currentRole; + private SchemaDescriptor currentDefaultSchema; + + public SQLSessionContextImpl (SchemaDescriptor sd) { + currentRole = null; + currentDefaultSchema = sd; + } + + public void setRole(String role) { + currentRole = role; + } + + public String getRole() { + return currentRole; + } + + public void setDefaultSchema(SchemaDescriptor sd) { + currentDefaultSchema = sd; + } + + public SchemaDescriptor getDefaultSchema() { + return currentDefaultSchema; + } +} Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/SQLSessionContextImpl.java ------------------------------------------------------------------------------ svn:eol-style = native 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=643920&r1=643919&r2=643920&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 Wed Apr 2 07:35:37 2008 @@ -47,6 +47,7 @@ import org.apache.derby.iapi.sql.ResultSet; import org.apache.derby.iapi.sql.compile.Optimizer; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.iapi.sql.conn.SQLSessionContext; import org.apache.derby.iapi.sql.depend.DependencyManager; import org.apache.derby.iapi.sql.dictionary.TableDescriptor; import org.apache.derby.iapi.sql.execute.ConstantAction; @@ -140,33 +141,38 @@ private int[] autoGeneratedKeysColumnIndexes ; private String[] autoGeneratedKeysColumnNames ; - // Authorization stack frame, cf. SQL 2003 4.31.1.1 and 4.27.3 is - // implemented as follows: Statements at root connection level - // (not executed within a stored procedure), maintain the current - // role in the lcc. In this case, 'callActivation' is null. If - // we are executing SQL inside a stored procedure (nested - // connection), then 'callActivation' will be non-null, and we - // maintain the current role in the activation of the calling - // statement, see 'setNestedCurrentRole'. The current role of a call - // context is kept in the field 'nestedCurrentRole'. - // - // 'callActivation' is set when activation is created (see - // GenericPreparedStatement#getActivation based on the top of the - // dynamic call stack of activation, see - // GenericLanguageConnectionContext#getCaller. - // - // Corner case: When a dynamic result set references current role, - // the value retrieved will always be that of the current role - // when the statement is executed (inside), not the current value - // when the result set is accessed outside the stored procedure. - // - // Consequence of this implementation: If more than one nested - // connection is used inside a shared procedure, they will share - // the current role setting. Since the same dynamic call context - // is involved, this seems correct. - // + /** + * The 'callActivation' of an activation of a statement executing in + * the root connection is null. + * + * A non-null 'callActivation' represents the activation of the + * calling statement. + * + * 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 + * 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 + * @see org.apache.derby.impl.sql.compile.StaticMethodCallNode#generateSetupNestedSessionContext + * + */ private Activation callActivation; - private String nestedCurrentRole; + + /** + * 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. + */ + private SQLSessionContext nestedSQLSessionContext; //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. @@ -1333,25 +1339,17 @@ } /** - * Set the current role name of the dynamic call context stemming - * from this activation (which must be a stored - * procedure/function call). - * - * @param role The name of the current role + * 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. */ - public void setNestedCurrentRole(String role) { - nestedCurrentRole = role; - } + public SQLSessionContext getNestedSQLSessionContext() { - /** - * Get the current role name of the dynamic call context stemming - * from this activation (which must be a stored - * procedure/function call). - * - * @return The name of the current role - */ - public String getNestedCurrentRole() { - return nestedCurrentRole; + if (nestedSQLSessionContext == null) { + nestedSQLSessionContext = lcc.createSQLSessionContext(); + } + + return nestedSQLSessionContext; } /** Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java Wed Apr 2 07:35:37 2008 @@ -781,6 +781,7 @@ { subqueryTrackingArray = statementContext.getSubqueryTrackingArray(); } + statementContext.setActivation(activation); } } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java Wed Apr 2 07:35:37 2008 @@ -73,25 +73,7 @@ { setup(); - LanguageConnectionContext lcc = - activation.getLanguageConnectionContext(); - - // Push the "authorization stack" of SQL 2003, vol 2, section - // 4.34.1.1 and 4.27.3. - lcc.pushCaller(activation); - - // Copy the current role into top cell of stack. Activations - // inside nested connections look to this activation for - // keeping its current role rather than rely on what's in lcc - // (top level only). - activation.setNestedCurrentRole(lcc.getCurrentRoleId(activation)); - - try { - methodCall.invoke(activation); - } - finally { - activation.getLanguageConnectionContext().popCaller(); - } + methodCall.invoke(activation); } /** Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropSchemaConstantAction.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropSchemaConstantAction.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropSchemaConstantAction.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropSchemaConstantAction.java Wed Apr 2 07:35:37 2008 @@ -96,7 +96,7 @@ SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, null, true); - sd.drop(lcc); + sd.drop(lcc, activation); } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetSchemaConstantAction.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetSchemaConstantAction.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetSchemaConstantAction.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetSchemaConstantAction.java Wed Apr 2 07:35:37 2008 @@ -121,6 +121,6 @@ SchemaDescriptor sd = dd.getSchemaDescriptor(thisSchemaName, lcc.getTransactionExecute(), true); - lcc.setDefaultSchema(sd); + lcc.setDefaultSchema(activation, sd); } } Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java?rev=643920&r1=643919&r2=643920&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java Wed Apr 2 07:35:37 2008 @@ -31,6 +31,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.apache.derbyTesting.junit.BaseJDBCTestCase; +import org.apache.derbyTesting.junit.JDBC; import org.apache.derbyTesting.junit.DatabasePropertyTestSetup; import org.apache.derbyTesting.junit.JDBC; import org.apache.derbyTesting.junit.TestConfiguration; @@ -70,6 +71,7 @@ private final static String revokeWarn = "01007"; private final static String notIdle = "25001"; private final static String invalidRoleName = "4293A"; + private final static String userException = "38000"; private int MAX_IDENTIFIER_LENGTH = 128; /** @@ -431,12 +433,6 @@ doStmt("set role 'FOO'", sqlAuthorizationRequired, null, null); - // JSR169 cannot run with tests with stored procedures that do - // database access - for they require a DriverManager connection to - // jdbc:default:connection; DriverManager is not supported with JSR169 - if (!JDBC.vmSupportsJSR169()) - doSetRoleInsideStoredProcedures("FOO"); - doStmt("set role none", sqlAuthorizationRequired, null , null); @@ -464,6 +460,10 @@ sqlAuthorizationRequired, null , null); assertRoleInRs(rs, "ROLE", "BAR"); + if (rs != null) { + rs.close(); + } + /* * REVOKE role */ @@ -774,7 +774,7 @@ try { pstmt.setString(1, "BAR"); int rowcnt = pstmt.executeUpdate(); - assertEquals(rowcnt, 0, "rowcount from set role ? not 0"); + assertEquals("rowcount from set role ? not 0", rowcnt, 0); } catch (SQLException e) { fail("execute of set role ? failed: [foo]" + e); } @@ -783,7 +783,7 @@ try { pstmt.setString(1, null); int rowcnt = pstmt.executeUpdate(); - assertEquals(rowcnt, 0, "rowcount from set role ? not 0"); + assertEquals("rowcount from set role ? not 0", rowcnt, 0); } catch (SQLException e) { fail("execute of set role ? failed: [NONE] " + e); } @@ -795,7 +795,7 @@ try { pstmt.setString(1, "NONE"); int rowcnt = pstmt.executeUpdate(); - assertEquals(rowcnt, 0, "rowcount from set role ? not 0"); + assertEquals("rowcount from set role ? not 0", rowcnt, 0); ResultSet rs = doQuery("values current_role", n_a, null , n_a ); assertRoleInRs(rs, "NONE", n_a); rs.close(); @@ -815,57 +815,12 @@ /* Test that current role is handled correctly when inside a * stored procedure. The SQL standard requires we have an - * "authorization stack", see section 4.34.1.1. This implies that - * current role is popped at end of stored procedure. - * We test two levels deep. + * "authorization stack", see section 4.34.1.1 and + * 4.27.3. Initially tested here, but now moved to + * lang/SQLSessionContextTest. */ - private void doSetRoleInsideStoredProcedures(String currRole) - throws SQLException - { - if (_authLevel != NO_SQLAUTHORIZATION) { - String n_a = null; // auth level not used for this test - doStmt("create procedure p2(role varchar(255))" + - " dynamic result sets 1 language java parameter style java"+ - " external name 'org.apache.derbyTesting." + - "functionTests.tests.lang.RolesTest.p2'" + - " modifies sql data", - n_a, null, null); - doStmt("create function f2(role varchar(255))" + - " returns int language java parameter style java" + - " external name 'org.apache.derbyTesting." + - "functionTests.tests.lang.RolesTest.f2'" + - " reads sql data", - n_a, null, null); - doStmt("call p2('" + currRole + "')", - n_a , null , null ); - - // Dynamic result set: At what time should CURRENT_ROLE be - // evaluated? Logically at the inside, so it should be - // "BAR" also when accessed on outside. I think. Anyway, - // that's what's implemented: the activation of the call - // is still live and holds the current role as it was - // inside the nested scope even when the procedure call - // has returned. - ResultSet prs = _stm.getResultSet(); - assertRoleInRs(prs, "BAR", "BAR"); - prs.close(); - - // check that role didn't get impacted by change inside p2 - // too 'BAR': - ResultSet rs = doQuery("values current_role", - n_a , null , null ); - assertRoleInRs(rs, currRole, currRole); - rs.close(); - rs = doQuery("values f2('" + currRole + "')", - n_a , null , null ); - rs.close(); - - doStmt("drop procedure p2", n_a, null, null); - doStmt("drop function f2", n_a, null, null); - } - } private void assertSystableRowCount(String table, int rcNoAuth, @@ -953,9 +908,10 @@ println("SYS.SYSROLES:"); while (rs.next()) { - println("r=" + rs.getString(1) + " -ee:" + rs.getString(2) + - " -or:" + rs.getString(3) + " a:" + rs.getString(4) + - " d:" + rs.getString(5)); + println("uuid=" + rs.getString(1) + + " r=" + rs.getString(2) + " -ee:" + rs.getString(3) + + " -or:" + rs.getString(4) + " a:" + rs.getString(5) + + " d:" + rs.getString(6)); } rs.close(); @@ -1036,45 +992,14 @@ if (_authLevel == NO_SQLAUTHORIZATION) { assertNull(rs); } else { - assertTrue("result set empty", rs.next()); - String actualRole = rs.getString(1); - if (isDbo()) { - assertTrue("role is " + actualRole + ", expected " + dboRole, - dboRole.equals(actualRole)); + JDBC.assertSingleValueResultSet(rs, dboRole); } else { - assertTrue("role is " + actualRole + ", expected " + notDboRole, - notDboRole.equals(actualRole)); + JDBC.assertSingleValueResultSet(rs, notDboRole); } - - // cardinality should be 1 - assertFalse("result set not empty", rs.next()); - } - } - - private void assertEquals(int a, int b, String txt) - { - if (a!=b) { - fail(txt); } } - private static void assertRsSingleStringValue(ResultSet rs, - String expectedValue) - throws SQLException - { - - assertTrue("result set empty", rs.next()); - String actualValue = rs.getString(1); - - assertTrue("string is " + actualValue + ", expected " + expectedValue, - actualValue.equals(expectedValue)); - - // cardinality should be 1 - assertFalse("result set not empty", rs.next()); - } - - /** * Utility function used to test auto-drop of grant routine * permission to a role @@ -1082,160 +1007,6 @@ */ public static int f1() { - return 1; - } - - - /** - * Utility procedure used to test that current role - * is stacked correctly according to dynamic scope. - */ - public static void p2(String roleOutside, ResultSet[] rs1) - throws SQLException - { - Connection conn1 = null; - Connection conn2 = null; - - try { - conn1 = DriverManager.getConnection("jdbc:default:connection"); - PreparedStatement ps = - conn1.prepareStatement("values current_role"); - - // check that we inherit role correctly - ResultSet rs = ps.executeQuery(); - assertRsSingleStringValue(rs, roleOutside); - rs.close(); - - // set the role to something else - Statement stm = conn1.createStatement(); - stm.execute("set role bar"); - rs = ps.executeQuery(); - - // check that role got set - assertRsSingleStringValue(rs, "BAR"); - - // another nesting level to test authorization stack even more - stm.execute( - "create procedure calledNestedFromP2(role varchar(255))" + - " language java parameter style java" + - " external name 'org.apache.derbyTesting." + - "functionTests.tests.lang.RolesTest.calledNestedFromP2'" + - " modifies sql data"); - conn1.commit(); // need to be idle - stm.execute("call calledNestedFromP2('BAR')"); - - rs = ps.executeQuery(); - - // check that role didn't get impacted by change inside - // calledNestedFromP2 too 'FOO': - assertRsSingleStringValue(rs, "BAR"); - stm.execute("drop procedure calledNestedFromP2"); - - // Test that the role is shared by another nested - // connection also. - conn2 = DriverManager.getConnection("jdbc:default:connection"); - PreparedStatement ps2 = - conn2.prepareStatement("values current_role"); - ResultSet rs2 = ps2.executeQuery(); - assertRsSingleStringValue(rs2, "BAR"); - - // Pass out CURRENT_ROLE in a dynamic result set. - rs = ps.executeQuery(); - rs1[0] = rs; - - } finally { - - if (conn1 != null) { - try { - conn1.close(); - } catch (Exception e) { - } - } - - if (conn2 != null) { - try { - conn2.close(); - } catch (Exception e) { - } - } - } - - } - - /** - * Called from p2 so we get to test with a call stack 3 levels - * deep. - */ - public static void calledNestedFromP2(String roleOutside) - throws SQLException - { - Connection conn1 = null; - - try { - conn1 = DriverManager.getConnection("jdbc:default:connection"); - PreparedStatement ps = - conn1.prepareStatement("values current_role"); - - // check that we inherit role correctly - ResultSet rs = ps.executeQuery(); - assertRsSingleStringValue(rs, roleOutside); - rs.close(); - - // set the role to something else - Statement stm = conn1.createStatement(); - stm.execute("set role foo"); - rs = ps.executeQuery(); - - // check that role got set - assertRsSingleStringValue(rs, "FOO"); - - } finally { - if (conn1 != null) { - try { - conn1.close(); - } catch (Exception e) { - } - } - } - } - - - /** - * Utility function used to test that current role - * is stacked correctly according to scope. - */ - public static int f2(String roleOutside) throws SQLException - { - Connection conn1 = null; - - try { - conn1 = DriverManager.getConnection("jdbc:default:connection"); - PreparedStatement ps = - conn1.prepareStatement("values current_role"); - - // check that we inherit role correctly - ResultSet rs = ps.executeQuery(); - assertRsSingleStringValue(rs, roleOutside); - rs.close(); - - // set the role to something else - Statement stm = conn1.createStatement(); - stm.execute("set role bar"); - rs = ps.executeQuery(); - - // check that role got set - assertRsSingleStringValue(rs, "BAR"); - - } finally { - - if (conn1 != null) { - try { - conn1.close(); - } catch (Exception e) { - } - } - - } return 1; } }