PL/SQL: It’s all in the presentation! Tim Hall Oracle ACE Director Oracle ACE of the Year 2006 OCP DBA (7, 8, 8i, 9i, 10g, 11g) OCA PL/SQL Developer http://www.oracle-base.com Oracle PL/SQL Tuning (Rampant) Oracle Job Scheduling (Rampant) http://www.oracle-base.com PL/SQL: It’s all in the presentation! • Physical organization of objects • Present queries from APIs – Ref cursors – Table functions and pipelining • Presenting data as web services and XML – SOAP web services – XML over HTTP – REST web services http://www.oracle-base.com Physical organization of objects Schema Owner Tables API Owner PL/SQL APIs Views? Login User PHP APEX Java http://www.oracle-base.com .NET Physical organization of objects Schema Owner Tables API Owner API Owner PL/SQL APIs Login User PHP PL/SQL APIs Login User APEX Login User Java http://www.oracle-base.com .NET Why break things up like this? • All data access via presentation (API) layer. – – – – – Better security. Hides processing complexity from clients. Presentation layer is sharable between applications. Easier to tune and trace. Hides schema changes from client applications. • Table or Transactional APIs? – Transactional APIs are important to me. APIs that perform business functions and and are understandable by the business. – I feel table APIs are unnecessary, but if you like them use them. – Don’t present table APIs to the outside world. http://www.oracle-base.com How do we implement it? • Use existing techniques to abstract the data: – Packaged procedures and functions for data processing. – Ref cursors and pipelined table functions for data presentation. • schema_setup.sql http://www.oracle-base.com Without using APIs $conn = get_connection(); $sql = " ”; $stmt = $result = ($conn, $sql); ($stmt, OCI_DEFAULT); while ( $dname = $employees = ($stmt)) { ($stmt, "DNAME"); ($stmt, "EMPLOYEES"); } ($stmt); ($conn) basic_query.php http://www.oracle-base.com Do views help? • • • • Views do reduce complexity of code in client apps. I prefer not to expose views to client developers. Risk of client developers writing joins between views. How would a view affect the previous client code? v_emps_by_dept d.dname, (e.ename) dept d emp e d.dname d.dname; employees e.deptno = d.deptno web_view.sql http://www.oracle-base.com Using a view $conn = get_connection(); $sql = " ”; $stmt = $result = ($conn, $sql); ($stmt, OCI_DEFAULT); while ( $dname = $employees = ($stmt)) { ($stmt, "DNAME"); ($stmt, "EMPLOYEES"); } ($stmt); ($conn); view_query.php http://www.oracle-base.com Cursor variables (REF CURSOR) • What are they? – A pointer to current row in multi-row query. • Why are they useful? – Allow us to separate opening and processing of cursors. – Can be passed as parameters. • Why is that useful to us? – Allows us to pass resultsets to client applications • Is that all they can do? – No, but it gets boring pretty fast… • Do we have to define REF CURSOR types? – No. We can be lazy and use SYS_REFCURSOR type. http://www.oracle-base.com Returning a cursor from a function web_rc_api get_emps_by_dept l_cursor ; l_cursor d.dname, (e.ename) dept d JOIN emp e d.dname d.dname; employees e.deptno = d.deptno l_cursor; get_emps_by_dept; web_rc_api; / web_rc_api.sql http://www.oracle-base.com Using ref cursors $conn = get_connection(); $sql = " ”; $stmt = ($conn, $sql); $cursor = $result = $result = ($conn); ($stmt, ':rc', $cursor, -1, OCI_B_CURSOR); ($stmt, OCI_DEFAULT); ($cursor, OCI_DEFAULT); while ( $dname = $employees = ($stmt)) { ($stmt, "DNAME"); ($stmt, "EMPLOYEES"); } ($stmt); ($conn); rc_query.php http://www.oracle-base.com I don’t have a simple query. What so I do? • You could use a table function. • What’s one of those? – Functions that return collections are known as table functions. • How can that help me? – In combination with the TABLE function, they can be used in the FROM clause of a query like a regular table. tf_test.sql • For regular table functions, the collection must be defined using database OBJECT types. • Is that all I need to know? – Not really. You need to know about pipelining. http://www.oracle-base.com Pipelining table functions • A table function builds the entire collection before returning any data, while a pipelined table function “pipes” each row out as soon as it is created. • How does that help me? – It reduces first row lag… ptf_schema.sql, ptf_package.sql, ptf_query.sql – As the collection is never fully resident in memory, pipelining can produce a considerable memory saving. memory_usage.sql – Since 9i R2, the types used to define the pipelined table function can be defined in a package, but this method can produce management problems, so I prefer the explicit method. implicit_types.sql • But how does that really help me? – You can use PL/SQL to build the row then pass it out. http://www.oracle-base.com Defining a Pipelined table Function web_ptf_api.sql http://www.oracle-base.com Using a pipelined table function $conn = get_connection(); $sql = " ”; $stmt = $result = ($conn, $sql); ($stmt, OCI_DEFAULT); while ( $dname = $employees = ($stmt)) { ($stmt, "DNAME"); ($stmt, "EMPLOYEES"); } ($stmt); ($conn); ptf_query.php http://www.oracle-base.com Can we improve on this? • We can combine Pipelined Table Functions and Ref Cursors. web_rc_ptf_api.sql • How will that affect the client code? http://www.oracle-base.com RC & PTF together (rc_ptf_query.php) $conn = get_connection(); $sql = " ”; $stmt = ($conn, $sql); $cursor = $result = $result = ($conn); ($stmt, ':rc', $cursor, -1, OCI_B_CURSOR); ($stmt, OCI_DEFAULT); ($cursor, OCI_DEFAULT); while ( $dname = $employees = ($stmt)) { ($stmt, "DNAME"); ($stmt, "EMPLOYEES"); } ($stmt); ($conn); rc_ptf_query.php http://www.oracle-base.com What have we shown? • We can use APIs to hide complexity from client application developers. • How do we present queries from our APIs? – Ref cursors – Pipelined table functions – Views? • Remember: The technology dictates will and won’t want to do with APIs, not just our ideals. • Is that the only way we can present data from PL/SQL? – Certainly not… http://www.oracle-base.com Web Services and XML • eGov AU: Craig Thomler's personal eGovernment and Gov 2.0 thoughts and speculations from an Australian perspective • Overcoming public sector hurdles to Gov 2.0 http://egovau.blogspot.com/2009/10/overcoming-public-sector-hurdles-to-gov.html • Choice quotes: – "...people are generally most comfortable with the technologies they grew up with...” – "...government systems are struggling in some areas to keep up with the rate of change...” – "If our systems can't support Gov 2.0 initiatives then it is unlikely that our senior management will.” http://www.oracle-base.com Web Services and XML • What does this have to do with PL/SQL? – PL/SQL allows you to create web applications, without the learning curve of Java or .NET. – Oracle allows you to present existing PL/SQL code as web services with zero effort. – Oracle's web toolkit allows you to present data as XML really easily. – PL/SQL is mature, not legacy. http://www.oracle-base.com XML DB Native Web Services • Oracle XML DB Native Web Services present your PL/SQL as Simple Object Access Protocol (SOAP) web services. • Requires a single configuration step on the database. • Enabled for “schema” by granting: – GRANT XDB_WEBSERVICES TO user; • Optionally: – GRANT XDB_WEBSERVICES_OVER_HTTP TO user; – GRANT XDB_WEBSERVICES_WITH_PUBLIC TO user; --? • • • • • web_services_setup.sql XML DB auto-generates a WSDL file. We send a SOAP Request and get a SOAP Response returned. call_ws.pl (run it) Physical organization of schema keeps things neat. http://www.oracle-base.com Physical organization of objects Schema Owner Tables WS API Owner API Owner PL/SQL APIs PL/SQL APIs Login User Java .NET http://www.oracle-base.com APEX XML over HTTP • We can also present XML directly from the database. • First we define a Database Access Descriptor (DAD) to give a “schema” access to the web toolkit functionality. xml_api_setup.sql • Next we define a package to generate our XML. xml_api.sql (run it) • This is an incredibly simple way to get XML out of the database. • Once again, physical organization is important. http://www.oracle-base.com XML over HTTP (Semi-Static Data) • The previous method regenerates the XML each time the URL is called. • For semi-static data this is a waste of resources. • Solution? Generate once and re-present. • How? Place it in the XML DB file system. xml_db_setup.sql • Next we define a procedure to generate our XML. semi_static.sql • How do we access this file? HTTP, FTP access, WebDAV • This can reduce resource usages. http://www.oracle-base.com REST web services • The previous method is similar to Representational State Transfer (REST) web services, with the exception of the URL. • We can mimic REST web services using the EPG parameters: – PATH-ALIAS – PATH-ALIAS-PROCEDURE • • • • rest_api_setup.sql rest_api.sql REST Demo We can easily code REST web services directly from PL/SQL. http://www.oracle-base.com Summary • Physical organization of objects – Important for us to present business driven functionality. • Ref cursors – Allows us to hide complexity from client applications. • Table functions – Allow us to return complex data as if it were a simple query. • Presenting data as web services and XML is easy using PL/SQL – Presenting existing PL/SQL code as SOAP web services. – Producing REST web services from PL/SQL. • Which all keeps us relevant in the new world order. • Demo Code: http://www.oracle-base.com/workshops http://www.oracle-base.com