Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Theory, Practice & Methodology of Relational Database Design and Programming Copyright © Ellis Cohen 2002-2008 Maintaining Session State in the Data.

Similar presentations


Presentation on theme: "1 Theory, Practice & Methodology of Relational Database Design and Programming Copyright © Ellis Cohen 2002-2008 Maintaining Session State in the Data."— Presentation transcript:

1 1 Theory, Practice & Methodology of Relational Database Design and Programming Copyright © Ellis Cohen 2002-2008 Maintaining Session State in the Data Tier These slides are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. For more information on how you may use them, please see http://www.openlineconsult.com/db

2 2 © Ellis Cohen 2001-2008 Overview of Lecture Temporary Session Tables Package Variables Maintaining Session State in the Data Tier Multi-User & Virtual Connections Shared Multi-User Connections Adding Security to Multi-User Connection

3 3 © Ellis Cohen 2001-2008 Temporary Session Tables

4 4 © Ellis Cohen 2001-2008 Session-Specific Information It can be useful to maintain a collection of information separately for each user session We could store this information in tables: –Use a single table, and use the user's session id as part of the primary key –Use a separate table for each user session

5 5 © Ellis Cohen 2001-2008 Temporary Tables A temporary table Has a single CREATE TABLE definition A separate instance of the table is created for each separate database connection that accesses the table The instance of the table is deleted whether the database connected is closed. Assuming that every user session results in a separate connection to the DB, temporary session tables can be used to store user session-specific information

6 6 © Ellis Cohen 2001-2008 Defining Temporary Tables CREATE GLOBAL TEMPORARY TABLE SomeTable ( … ) ON COMMIT PRESERVE ROWS; Session Tables: Use ON COMMIT PRESERVE ROWS, which retains the data in each table instance from transaction to transaction (just like permanent tables) Transaction Tables: Use ON COMMIT DELETE ROWS which automatically empties the data in each table instance at the end of every transaction (this is the default, and is useful for holding temporary data during a transaction)

7 7 © Ellis Cohen 2001-2008 Using Session Tables Suppose our application has a number of user query operations which display information about products we want to keep track of every product we viewed in a session we want to be able to implement a query that shows the ids & names of all products we have viewed in the session so far

8 8 © Ellis Cohen 2001-2008 Remembering Seen Products CREATE GLOBAL TEMPORARY TABLE SeenProducts ( prodid int primary key references Products ) ON COMMIT PRESERVE ROWS; PROCEDURE RememberProduct( aProdid int ) IS BEGIN INSERT INTO SeenProducts VALUES( aProdid ); -- insert the product into the table to remember it -- if it's already there, ignore the exception! EXCEPTION WHEN OTHERS THEN NULL; END;

9 9 © Ellis Cohen 2001-2008 Remembering Displayed Products DECLARE productRec Products%ROWTYPE; BEGIN SELECT * INTO productRec FROM Products WHERE prodid = :prodid; pl( prodRec.prodnam ); pl( prodRec.description ); -- remember it! RememberProduct( :prodid ); EXCEPTION WHEN OTHERS THEN doerr(); END; ShowProduct( :prodid )

10 10 © Ellis Cohen 2001-2008 List Remembered Products SELECT prodid, prodnam FROM Products NATURAL JOIN SeenProducts; ListRememberedProducts If multiple users are connected to the database, each user will have their own copy of SeenProducts

11 11 © Ellis Cohen 2001-2008 Package Variables

12 12 © Ellis Cohen 2001-2008 Package Variables PL/SQL Packages can declare variables A separate instance of each package variable is created for each separate database connection that accesses the package. These can hold typed data in the data tier specific to a database connection.

13 13 © Ellis Cohen 2001-2008 Package Variable Visibility Variables can be declared in the package body: only accessible to procedures and functions also in the package body (i.e. private) the package description: also visible outside of the package. Package variables persistently hold data values for the lifetime of the connection

14 14 © Ellis Cohen 2001-2008 Package Variable Example SQL> CREATE OR REPLACE PACKAGE BODY MyUtil AS startdate date; -- package body variable FUNCTION getdate RETURN date IS BEGIN RETURN startdate; -- always returns the initial date -- dangerous if session lasts too long END; FUNCTION getNumColumns( tblnam varchar )... BEGIN -- package initialization SELECT sysdate INTO startdate FROM dual; END MyUtil; /

15 15 © Ellis Cohen 2001-2008 Package Variables & Sessions Suppose MyUtil is was created by a user connected to the database as EmpDB. While that user is logged in, another user also connects as EmpDB. What happens to MyUtil.startdate? Is it reinitialized?

16 16 © Ellis Cohen 2001-2008 Package Variables are Per-Connection Actually, each different connection to EmpDB will get its own private copy of MyUtil.startdate. And that private copy of MyUtil.startdate will be initialized the first time that MyUtil is accessed by code executed via that connection!

17 17 © Ellis Cohen 2001-2008 Package Body Exercise PACKAGE RememberedEmployee AS PROCEDURE Remember( IN anEmpno number ); -- remembers an employee's number FUNCTION GetEmp return number; -- returns the remembered employee's number FUNCTION GetJob RETURN varchar; -- returns the job of the remembered employee FUNCTION HasHigherSal( IN aSal number ) RETURN boolean; --- indicates whether the remembered employee has a salary higher than aSal END RememberedEmployee; Write the body!

18 18 © Ellis Cohen 2001-2008 Package Body Exercise Answer #1 PACKAGE BODY RememberedEmployee AS remEmpno emp.empno%TYPE; PROCEDURE Remember( IN anEmpno number ) IS BEGIN remEmpno := anEmpno; END; FUNCTION GetEmp RETURN number IS BEGIN RETURN remEmpno; END; FUNCTION GetJob RETURN varchar IS remJob emp.job%TYPE; BEGIN SELECT job INTO remJob FROM Emps WHERE empno = remEmpno; RETURN remJob; END; FUNCTION HasHigherSal( IN aSal number ) RETURN boolean IS remSal emp.sal%TYPE; BEGIN SELECT sal INTO remSal FROM Emps WHERE empno = remEmpno; RETURN (remSal > aSal); END; END RememberedEmployee;

19 19 © Ellis Cohen 2001-2008 Package Body Exercise Answer #2 PACKAGE BODY RememberedEmployee AS remEmpno emp.empno%TYPE; remJob emp.job%TYPE; remSal emp.sal%TYPE; PROCEDURE Remember( IN anEmpno number ) IS BEGIN remEmpno := anEmpno; SELECT job, sal INTO remJob, remSal FROM Emps WHERE empno = anEmpno; END; FUNCTION GetEmp RETURN number IS BEGIN RETURN remEmpno; END; FUNCTION GetJob RETURN varchar IS BEGIN RETURN remJob; END; FUNCTION HasHigherSal( IN aSal number ) RETURN boolean IS BEGIN RETURN (remSal > aSal); END; END RememberedEmployee; Dangerous if job or sal can be changed in Emps

20 20 © Ellis Cohen 2001-2008 Maintaining Session State in the Data Tier

21 21 © Ellis Cohen 2001-2008 Middle-Tier Session Variables EmpDB Middle-Tier :curuser 7782 App User 7782 Middle-Tier :curuser 6419 App User 6419

22 22 © Ellis Cohen 2001-2008 Session Variable Placement We've been assuming that middle-tier session variables are the best place to maintain some per-session information such as :curuser Are there any reasons to instead (or also) maintain this information in the data-tier (i.e. in the database?)

23 23 © Ellis Cohen 2001-2008 Data Tier Placement Data tier placement enables –Session recovery on middle-tier crash –Session migration for load balancing –Simpler reusable views and procedures

24 24 © Ellis Cohen 2001-2008 Package Variables & Session Data Assuming that every user session uses a separate connection to the DB Then package variables can be used to store user session data

25 25 © Ellis Cohen 2001-2008 Data-Tier Session Variables EmpDB Middle-Tier :curuser 7782 App User 7782 Middle-Tier :curuser 6419 App User 6419 curuser 7782 curuser 6419 Data-tier session variables are implemented as package variables, which are maintained separately for each session! With curuser as a package variable

26 26 © Ellis Cohen 2001-2008 AuthPkg Example Suppose our application defines AuthPkg to register and login users, and to keep track of the current user in each session, with operations: PROCEDURE Register( aUser, aPwd, aRole ) PROCEDURE Login( usr, pwd, theRole ) PROCEDURE Logout FUNCTION GetUser RETURN int -- returns logged in user (or NULL) OUT parameter

27 27 © Ellis Cohen 2001-2008 AuthPkg Body CREATE TABLE AuthUsers( userid int PRIMARY KEY, passwd varchar(128), role varchar(30) ); CREATE PACKAGE BODY AuthPkg AS curuser int; PROCEDURE Register( aUser int, aPwd varchar, aRole varchar ) IS BEGIN INSERT INTO AuthUsers VALUES( aUser, aPwd, aRole ); END; PROCEDURE Login( usr int, pwd varchar, theRole OUT char ) IS BEGIN SELECT role INTO theRole FROM AuthUsers WHERE userid = usr AND passwd = pwd; curuser := usr; END; PROCEDURE Logout IS BEGIN curuser := NULL; END; FUNCTION GetUser RETURNS int IS BEGIN RETURN curuser; END; … END AuthPkg; Each DB session (i.e. connection) has its own instance of package variables. So curuser has a value specific to the connected DB session

28 28 © Ellis Cohen 2001-2008 Using AuthPkg in Login DECLARE theRole varchar(30); BEGIN AuthPkg.Login( :userid, :pwd, theRole ); pl( 'Logged in with role ' || theRole ); END; Login( :userid, :pwd ) OUT parameter Returns the role

29 29 © Ellis Cohen 2001-2008 Using Script Variables DECLARE theRole varchar(30); BEGIN AuthPkg.Login( &1, &2, theRole ); pl( 'Logged in with role ' || theRole ); END; Login( :userid, :pwd ) &1 -- :userid &2 -- :pwd

30 30 © Ellis Cohen 2001-2008 ShowSals using :curuser SELECT empno, ename, sal FROM Emps WHERE empno = :curuser OR mgr = :curuser ShowSals Shows employee #, name & salary of the current user and of all employees the current user directly manages (using the middle tier variable :curuser) Assuming that the identity of :curuser was only maintained in the data-tier package AuthPkg, rewrite ShowSals

31 31 © Ellis Cohen 2001-2008 ShowSals using AuthPkg SELECT empno, ename, sal FROM Emps WHERE empno = AuthPkg.GetUser OR mgr = AuthPkg.GetUser ShowSals Shows employee #, name & salary of current user and all employees the current user directly manages! Keeping track of the identity of the current user in the data-tier is known as Data-Tier Identity

32 32 © Ellis Cohen 2001-2008 Caching Session Variables in the Middle Tier DECLARE theRole varchar(30); BEGIN AuthPkg.Login( :userid, :pwd, :currole ); :curuser := :userid; pl( 'Logged in with role ' || :currole ); END; Login( :userid, :pwd ) SELECT empno, ename, sal FROM Emps WHERE empno = :curuser OR mgr = :curuser ShowSals Write a view showing the employee #s & names of all employee managed by the current user

33 33 © Ellis Cohen 2001-2008 Session-Based Views CREATE CurManageView AS SELECT empno, ename FROM Emps WHERE mgr = :curuser CREATE CurManageView AS SELECT empno, ename FROM Emps WHERE mgr = AuthPkg.GetUser Middle-tier session variables can't be used in views. There's no way for the database to access them!

34 34 © Ellis Cohen 2001-2008 Multi-User & Virtual Connections

35 35 © Ellis Cohen 2001-2008 Per-User DB Connection EmpDB Middle-Tier :curuser 7782 App User 7782 Middle-Tier :curuser 6419 App User 6419 curuser 7782 curuser 6419

36 36 © Ellis Cohen 2001-2008 User Sessions & DB Connections In real systems Does the middle tier maintain a separate connection to the DB for each separate application user session?

37 37 © Ellis Cohen 2001-2008 Database Connections Database connections are expensive Web/App servers typically use a small pool of connections, which are used for requests. Database Server App Server Connections

38 38 © Ellis Cohen 2001-2008 Virtual Connections Some databases (e.g. Oracle) support virtual connections There are still only a small # of "physical" connections between the Web/App server and the database It's possible to code as if there were a separate connection for each application user Separate temporary tables and package variable instances are created for each virtual connection

39 39 © Ellis Cohen 2001-2008 Shared Multi-User Connections

40 40 © Ellis Cohen 2001-2008 Using Shared Connections If –a middle tier server uses connection pooling –virtual connections are not used then –it is not possible to associate a single user id with a connection The middle-tier server –gets requests from different application users –ships them over a shared connection to the database server –Although this requires each request to be a separate transaction

41 41 © Ellis Cohen 2001-2008 Switching Users The middle tier processes requests on behalf of the various users. Suppose that :requser is the identity of the user whose request is being processed. Before executing the operation code to implement the request, the middle tier must switch the current user (for that connection) to be :requser If :curuser is maintained in the middle tier, the middle tier executes :curuser := :requser If curuser is mantained in AuthPkg, the middle tier sets the curuser package variable to hold the identity of :requser by calling AuthPkg.SwitchUser( :requser )

42 42 © Ellis Cohen 2001-2008 AuthPkg with User Switching CREATE PACKAGE BODY AuthPkg AS curuser int; … PROCEDURE Login( usr int, pwd varchar, theRole OUT char ) IS BEGIN SELECT role INTO theRole FROM AuthUsers WHERE userid = usr AND passwd = pwd; curuser := usr; END; PROCEDURE Logout IS BEGIN curuser := NULL; END; PROCEDURE SwitchUser( requsr int ) IS curuser := requsr; … END AuthPkg;

43 43 © Ellis Cohen 2001-2008 ShowSals w User Switching AuthPkg.SwitchUser( :requser ) SELECT ename, sal FROM Emps WHERE empno = AuthPkg.GetUser OR mgr = AuthPkg.GetUser ShowSals

44 44 © Ellis Cohen 2001-2008 Adding Security to Multi-User Connections

45 45 © Ellis Cohen 2001-2008 Adding Security Requests should only be able to be made on behalf of users who have logged in and not logged out. If we can ensure this, it can help protect against –Application Server Errors –Hackers who might tap into the application server or the database connection

46 46 © Ellis Cohen 2001-2008 AuthPkg Body CREATE TABLE CurUsers( userid int primary key ); CREATE PACKAGE BODY AuthPkg AS curuser int; PROCEDURE Login( usr int, pwd varchar, theRole OUT char ) IS BEGIN SELECT role INTO theRole FROM AuthUsers WHERE userid = usr AND passwd = pwd; curuser := usr; INSERT INTO CurUsers VALUES( usr ); END; PROCEDURE Logout IS BEGIN DELETE FROM CurUsers WHERE userid = curuser; curuser := NULL; END; PROCEDURE SwitchUser( requsr int ) IS SELECT userid INTO curuser FROM CurUsers WHERE userid = requsr; … END AuthPkg; Checks that user is actually logged in This version of the code ensures that a user can only have one session. Why? How could you allow multiple sessions per user?

47 47 © Ellis Cohen 2001-2008 User Assignment The middle tier could assign a request from any user to any connection Suppose when a user logged in, the middle tier assigned that user to a specific connection, and then directs all requests by that user to the same connection. Then, a request to SwitchUser should only work if it was on the same connection on which the user logged in. Change AuthPkg accordingly

48 48 © Ellis Cohen 2001-2008 CREATE GLOBAL TEMPORARY TABLE CurUsers( userid int primary key ) ON COMMIT PRESERVE ROWS; CREATE PACKAGE BODY AuthPkg AS curuser int; … PROCEDURE Login( usr int, pwd varchar, theRole OUT char ) IS BEGIN SELECT role INTO theRole FROM AuthUsers WHERE userid = usr AND passwd = pwd; curuser := usr; INSERT INTO CurUsers VALUES( usr ); END; PROCEDURE Logout IS BEGIN DELETE FROM CurUsers WHERE userid = curuser; curuser := NULL; END; PROCEDURE SwitchUser( requsr int ) IS SELECT userid INTO curuser FROM CurUsers WHERE userid = requsr; … END AuthPkg; AuthPkg with User Assignment (1) Checks that the user is actually logged in on that connection Maintains separate table for each connection This depends upon trusting that the middle tier will not login the same user on multiple connections

49 49 © Ellis Cohen 2001-2008 CREATE TABLE CurUsers( userid int primary key, sessid int ); CREATE PACKAGE BODY AuthPkg AS curuser int; … PROCEDURE Login( usr int, pwd varchar, theRole OUT char ) IS BEGIN INSERT INTO CurUsers VALUES( usr, SYS_CONTEXT( 'USERENV', 'SESSIONID') ); SELECT role INTO theRole FROM AuthUsers WHERE userid = usr AND passwd= pwd; curusr := usr; END; PROCEDURE Logout IS BEGIN DELETE FROM CurUsers WHERE userid = curuser; curuser := NULL; END; PROCEDURE SwitchUser( requsr int ) IS SELECT userid INTO curuser FROM CurUsers WHERE userid = requsr AND sessid = SYS_CONTEXT( 'USERENV', 'SESSIONID'); … END AuthPkg; AuthPkg with User Assignment (2) Remembers the connection to which the Login request was sent. Raises exception if user logged in more than once Checks that the request is in the same connection where the user was logged in


Download ppt "1 Theory, Practice & Methodology of Relational Database Design and Programming Copyright © Ellis Cohen 2002-2008 Maintaining Session State in the Data."

Similar presentations


Ads by Google