Friday Mar 14, 2014

Performance improvement for OCI_RETURN_LOBS in PHP OCI8 2.0.8

Reducing "round trips" to the database server is important for performance and ultimately for system scalability. A server round-trip is defined as the trip from PHP to the database server and back to PHP.

Reducing round trips makes everything more efficient: PHP is faster, there is less network overhead, the database doesn't have to do a context switch or do any processing for you. Applications have some control over round trips, for example by effectively using prefetching or by using an appropriate execute mode to minimize unneccessary rollbacks at the end of a script.

The bug filer of Bug 66875 noticed that PHP OCI8's implementation itself could reduce round trips if a particular LOB column meta data value was cached for the duration of a query instead of being re-requested for each row of the query result set.

So, now with OCI8 2.0.8, you should see a performance increase if you are doing multi-row queries involving LOB columns returned as OCI_RETURN_LOBS:

$s = oci_parse($c, "select mylobcol from mylobtab");
oci_execute($s);
while (($row = oci_fetch_array($s, OCI_ASSOC+OCI_RETURN_LOBS)) !== false) {
    echo $row['MYLOBCOL'], "\n";
}

The bug filer tested the patch and added his performance improvement benchmark results to the bug report. The benefit in your environment will vary greatly with the network setup, schema, and how many LOB columns are queried. Test it out and let me know how the new version helps you.

There is no immediate change for LOBs fetched with OCI-Lob::read() and OCI-Lob::load(). This would require a more complex patch than I want to apply at this time. Queries that don't use LOBs are not affected in any way by the patch.

OCI8 2.0 is included in the forthcoming PHP 5.6 code base. For PHP 5.2 to PHP 5.5 you can install it from PECL. PHP 5.5 RPMs with PHP OCI8 2.0.8 are available from oss.oracle.com.

Finally, if your LOB queries return multiple rows, you might also like this tip to reduce PHP memory usage.

Monday Mar 03, 2014

The Oracle Database Access Group is hiring

Over the years I've worked very closely with the Oracle Database Access Group and have a lot of respect for them. I'm happy to share that they are hiring C developers.

To apply, go to irecruitment.oracle.com and enter the code IRC2401606 or IRC2403582 (depending where you want to work) in the Keyword search box.

Here is an excerpt from the job posting:

The Database Access group at Oracle is responsible for providing functionally comprehensive, reliable, high performance, secure and highly available access to the Oracle Database from various client drivers, including proprietary, standards-based and open-source drivers. The group works on the high level drivers, the Oracle Call Interface (OCI) layer, the Oracle wire protocol (TTC) and highly scalable server side protocol handlers that together connect an application written in any language securely to the Oracle Database Server to provide full featured access to the Oracle Database.

Some of the listed requirements are:

  • Strong C programming experience.

  • Knowledge and experience with latest application development technologies including open source and web technologies (e.g. PHP, Ruby, Python, Node.js, HTML5, JavaScript)

I believe it when they also say "Work is non-routine and very complex, involving the application of advanced technical/business skills in area of specialization". Check out the postings for all the details. I look forward to working with you.

Addendum: IRC2401606 is also available.

Tuesday Feb 11, 2014

Support for binding Oracle PL/SQL BOOLEAN introduced in PHP OCI8 2.0.7

I've released PHP OCI8 2.0.7 which has oci_bind_by_name() support for binding PL/SQL's BOOLEAN type to PHP's boolean. The feature is available when PHP OCI8 2.0.7 is linked-with and connects-to Oracle Database 12c. (The necessary Oracle C library support for binding BOOLEAN was introduced in 12c).

Following the existing PHP OCI8 convention, there are two new constants usable with oci_bind_by_name(): SQLT_BOL and OCI_B_BOL. They have identical values. The former mirrors the underlying Oracle library constant's name (yes, it only has one "O"). The latter follows the PHP OCI8 style of having OCI_B_-prefixed names for bind constants. Note the constants can't be used for array binding with oci_bind_array_by_name().

An example usng the new PHP OCI8 2.0.7 feature is:

<?php

/*
  Precreate this PL/SQL function:
    create or replace function is_valid(p in number) return boolean as
    begin
      if (p < 10) then
        return true;
      else
        return false;
      end if;
    end;
    /

*/

$c = oci_connect('hr', 'welcome', 'localhost/pdborcl');

$sql = "begin :r := is_valid(40); end;";
$s = oci_parse($c, $sql);
oci_bind_by_name($s, ':r', $r, -1, SQLT_BOL);  // no need to give length
oci_execute($s);
var_dump($r);                                  // Outputs: bool(false)

?>

Prior to OCI8 2.0.7 you had to write a wrapper PL/SQL block that mapped the PL/SQL true or false values to 1 or 0.

Code without using OCI8 2.0.7:

$sql = "begin if (is_valid(40) = true) then :r := 1; else :r := 0; end if; end;";
$s = oci_parse($c, $sql);
oci_bind_by_name($s, ':r', $r, -1, SQLT_INT);
oci_execute($s);
echo "Result is " . ($r ? "true" : "false") . "\n";  // Outputs: Result is false

The new functionality removes one small pain point and makes your interaction with Oracle Database 12c PL/SQL cleaner and easier.

Thursday Oct 24, 2013

PHP PECL OCI8 2.0 Production Release Announcement

The PHP OCI8 2.0.6 extension for Oracle Database is now "production" status. The source code is available on PECL. This can be used immediately to update your OCI8 extension in PHP 5.2 and later versions. The extension compiles with Oracle 10.2 or later client libraries. Oracle's standard cross-version database connectivity applies.

OCI8 2.0 and PHP 5.5.5 RPMs for Oracle and Red Hat Linux are available from oss.oracle.com. Windows DLLs are available on PECL for PHP 5.3, PHP 5.4 and PHP 5.5.

OCI8 2.0 source code will also be automatically included in the next major version of PHP.

New Functionality

  • Oracle Database 12c Implicit Result Set support. IRS's make it easy to pass query results back from stored PL/SQL procedures or anonymous PL/SQL blocks. Individual IRS statement resources, each corresponding to a single query, can be obtained with the new function oci_get_implicit_resultset(). These 'child' statement resources can be passed to any oci_fetch_* function. See Using PHP and Oracle Database 12c Implicit Result Sets and the PHP Manual: oci_get_implicit_resultset().

  • DTrace Dynamic Trace static probes. This well respected DTrace tracing framework is available on a number of platforms, including Oracle Linux. PHP OCI8 static user-space probes can be enabled with PHP's --enable-dtrace configuration option. See Using PHP DTrace on Oracle Linux. Documentation is also available in the PHP Manual OCI8 and DTrace Dynamic Tracing

Improved Functionality

  • Using oci_execute($s, OCI_NO_AUTO_COMMIT) for a SELECT no longer unnecessarily initiates an internal ROLLBACK during connection close. This can improve overall scalability by reducing "round trips" between PHP and the database.

Changed Functionality

  • PHP OCI8 2.0's minimum pre-requisites are now PHP 5.2 and Oracle client library 10.2. Later versions of both are usable and, in fact, recommended. Use the older PHP OCI8 1.4.10 extension when using PHP 4.3.9 through to PHP 5.1.x, or when only Oracle Database 9.2 client libraries are available.

  • oci_set_*($connection, ...) meta data setting call error handling is fixed so that oci_error($connection) works for these calls.

Note: The old, deprecated function aliases like ocilogon still exist but are not recommended for new applications.

Phpinfo() Changes

Some cosmetic changes were made to the output of php --ri oci8 and the phpinfo() function.

  • The oci8.event and oci8.connection_class values are now shown only when the Oracle client libraries support the respective functionality.

  • Connection statistics are now in a separate phpinfo() table.

  • Temporary LOB and Collection support status lines in phpinfo() output were removed. These two features have always been enabled since 2007.

Oci_internal_debug() Changes

  • The oci_internal_debug() function is now a no-op. Use PHP's --enable-dtrace functionality with DTrace or SystemTap instead.

References

Monday Sep 09, 2013

Using PHP DTrace on Oracle Linux

This post shows PHP and DTrace "dynamic tracing" in action on Oracle Linux. It follows my previous post on recent PHP patches to stabilize DTrace support.

Install Oracle Linux and the UEK3 Kernel

  1. The starting point is to install Oracle Linux 6.4 from Oracle eDelivery. Wim Coekaerts blogged about the UEK3 release. I'm going to quote a paragraph from Wim here because it is fundamental to understanding Oracle Linux's direction:

    Oracle Linux is freely downloadable from http://edelivery.oracle.com/linux. Oracle Linux is free to use on as many systems as you want, is freely re-distributable without changing the CD/ISO content (so including our cute penguin), provides free security errata and bugfix errata updates. You only need to pay for a support subscription for those systems that you want/need support for, not for other systems. This allows our customers/users to run the exact same software on test and dev systems as well as production systems without having to maintain potentially two kinds of repositories. All systems can run the exact same software all the time.

  2. Once OL 6.4 is installed, add the Beta repo with:

    # cd /etc/yum.repos.d
    # mv public-yum-ol6.repo public-yum-ol6.repo.disabled
    # wget http://public-yum.oracle.com/beta/public-yum-ol6-beta.repo
    
  3. Enable the UEK3 Beta channel by editing public-yum-ol6-beta.repo and setting "enabled" to 1.

    enabled=1
  4. Install the UEK3 kernel, which supports DTrace:

    # yum update
  5. Install the DTrace utilities:

    # yum install dtrace-utils
  6. Reboot to the new UEK3 3.8.13 kernel

Install PHP

[Update: see DTrace PHP Using Oracle Linux 'playground' Pre-Built Packages for some pre-built PHP RPMs.]

  1. Download a PHP snapshot (or PHP 5.4.20 or PHP 5.5.4, when they become available) from snaps.php.net and extract it:

    $ tar -xJf php5.5-201309042230.tar.xz
    $ cd php5.5-201309042230
  2. Configure PHP:

    $ ./configure \
      --prefix=$HOME/p55 \
      --enable-dtrace \
      --disable-all --disable-cgi \
      --with-pear --enable-xml --enable-libxml --with-zlib

    This builds a minimal command line PHP with DTrace enabled. All unwanted extensions are disabled. You can include other extensions as needed. Currently PHP DTrace testing is limited to command-line use because a UEK3 DTrace fix for forked environments wasn't available at the time of the UEK3 Beta 1 release.

    The --prefix option puts the installation into a local directory, which makes it easy to see the files installed. It is easy to cleanup this directory when finished with the snapshot.

    The PEAR, XML and Zlib options allow the use of the 'pecl' command.

  3. Make the PHP binary and install it:

    $ make
    $ make install
  4. Copy php.ini-development to $HOME/p55/lib/php.ini and edit it to set the timezone, for example:

    date.timezone = America/Los_Angeles

Install PHP OCI8 for Oracle Database

To connect to Oracle Database, add PHP OCI8 as a "shared" extension:

  1. Download Oracle Instant Client "basic" and "devel" RPMs from ULN (for ULN subscribers) or OTN. You can use the 10g, 11g or 12c versions.

  2. Install Instant Client as root:

    # rpm -Uvh oracle-instantclient12.1-basic-12.1.0.1.0-1.x86_64.rpm
    # rmp -Uvh oracle-instantclient12.1-devel-12.1.0.1.0-1.x86_64.rpm
  3. As a normal user, set PATH so PHP is found:

    $ export PATH=$HOME/p55/bin:$PATH
  4. Set a PEAR proxy, if needed for access to http://pecl.php.net:

    $ pear config-set http_proxy http://myproxy.example.com:80/
  5. Set an environment variable PHP_DTRACE to enable DTrace, and install PHP OCI8:

    $ PHP_DTRACE=yes pecl install oci8-2.0.2

    The DTrace probes definitions used later in this article are based on PHP OCI8 2.0.2, so that explicit version is installed. If you install any future, later version review the probes and their arguments for differences. Note PHP OCI8 2.0 is in "development" status so changes are likely.

    When prompted for the ORACLE_HOME directory, hit return without entering text. The installation will autodetect the Instant Client RPMs. Configuration will continue and the output will contain something like:

    [ . . . ]
    checking for Oracle Database OCI8 support... yes, shared
    checking PHP version... 5.5.4, ok
    checking OCI8 DTrace support... yes
    [ . . . ]
    configure: WARNING: OCI8 extension: ORACLE_HOME is not set,
        looking for default Oracle Instant Client instead
    checking Oracle Instant Client directory...
        /usr/lib/oracle/12.1/client64/lib
    checking Oracle Instant Client SDK header directory...
       /usr/include/oracle/12.1/client64
    checking Oracle Instant Client library version compatibility... 12.1
    [ . . . ]
    
  6. Edit php.ini again and add PHP OCI8:

    extension=oci8.so
  7. Confirm the installation:

    $ php --ri oci8
    
    oci8
    
    OCI8 Support => enabled
    OCI8 DTrace Support => enabled
    OCI8 Version => 2.0.2-dev
    Revision => $Id: b30fb4bef45d9f5ce8a56b736f1546ea0cff08ef $
    Oracle Run-time Client Library Version => 12.1.0.1.0
    Oracle Compile-time Instant Client Version => 12.1
    
    Directive => Local Value => Master Value
    oci8.max_persistent => -1 => -1
    oci8.persistent_timeout => -1 => -1
    oci8.ping_interval => 60 => 60
    oci8.privileged_connect => Off => Off
    oci8.statement_cache_size => 20 => 20
    oci8.default_prefetch => 100 => 100
    oci8.old_oci_close_semantics => Off => Off
    oci8.connection_class => no value => no value
    oci8.events => Off => Off
    
    Statistics =>  
    Active Persistent Connections => 0
    Active Connections => 0

PHP OCI8 Installation Notes

For DTrace support, PHP OCI8 2.0 needs to be installed from PECL because PHP 5.4 and PHP 5.5 have PHP OCI8 1.4, which doesn't have DTrace probes. In future, when PHP 5.6 (or whatever comes after 5.5) is released, you will be able to configure a DTrace-enabled PHP OCI8 while building PHP.

You can, of course, install PHP OCI8 with Instant Client ZIP files, or simply use an existing ORACLE_HOME install.

You can DTrace-enable PHP OCI8 on a version of PHP that doesn't have DTrace available or configured. This includes older versions of PHP. You will be able to trace the PHP OCI8 probes but not any core PHP probes. Similarly you can install a DTrace-disabled PHP OCI8 on DTrace-enabled PHP.

If you install PHP OCI8 2.0 from PECL using 'phpize' and 'configure' (instead of 'pecl'), you will still need to set PHP_DTRACE=yes. This is because the --enable-dtrace option will be ignored by the limited 'configure' script of a PECL bundle.

The PHP OCI8 2.0 configuration script is suitable for "real" DTrace use but Linux SystemTap will not trace the extension.

Note that DTracing optimized binaries might give output that is not quite expected from code observation.

Verify the PHP DTrace Probes

  1. As root, enable DTrace and allow normal users to record trace information:

    # modprobe fasttrap
    # chmod 666 /dev/dtrace/helper

    Instead of the chmod, you could instead use an acl package rule to limit device access to a specific user.

  2. As a normal user, run php without any options. It will start and wait for input:

    $ php
  3. As root, list the DTrace probes that are available. Both PHP core and PHP OCI8 probes are listed:

    # dtrace -l -m php -m oci8.so
     4 php9559     php              dtrace_compile_file compile-file-entry
     5 php9559     php              dtrace_compile_file compile-file-return
     6 php9559     php                       zend_error error
     7 php9559     php ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caught
     8 php9559     php    zend_throw_exception_internal exception-thrown
     9 php9559     php                dtrace_execute_ex execute-entry
    10 php9559     php          dtrace_execute_internal execute-entry
    11 php9559     php                dtrace_execute_ex execute-return
    12 php9559     php          dtrace_execute_internal execute-return
    13 php9559     php                dtrace_execute_ex function-entry
    14 php9559     php                dtrace_execute_ex function-return
    15 php9559     php             php_request_shutdown request-shutdown
    16 php9559     php              php_request_startup request-startup
    17 php9559 oci8.so  php_oci_dtrace_check_connection oci8-check-connection
    18 php9559 oci8.so               php_oci_do_connect oci8-connect-entry
    19 php9559 oci8.so        php_oci_persistent_helper oci8-connect-expiry
    20 php9559 oci8.so            php_oci_do_connect_ex oci8-connect-lookup
    21 php9559 oci8.so php_oci_pconnection_list_np_dtor oci8-connect-p-dtor-close
    22 php9559 oci8.so php_oci_pconnection_list_np_dtor oci8-connect-p-dtor-release
    23 php9559 oci8.so               php_oci_do_connect oci8-connect-return
    24 php9559 oci8.so            php_oci_do_connect_ex oci8-connect-type
    25 php9559 oci8.so                    php_oci_error oci8-error
    26 php9559 oci8.so        php_oci_statement_execute oci8-execute-mode
    27 php9559 oci8.so             php_oci_create_spool oci8-sesspool-create
    28 php9559 oci8.so           php_oci_create_session oci8-sesspool-stats
    29 php9559 oci8.so           php_oci_create_session oci8-sesspool-type
    30 php9559 oci8.so         php_oci_statement_create oci8-sqltext
    

    The core PHP probes are documented here. ThePHP OCI8 probes are described below.

  4. In your user terminal, stop the php executable with Ctrl-C.

    $ php
    ^C
    $

PHP OCI8 2.0 DTrace Probe Overview

The static PHP OCI8 2.0 probes can be categorized as "user" probes and "maintainer" probes. The latter that are more useful for PHP OCI8 maintainers to verify functionality during development of the extension itself. All the probes return data in arguments.

User Probes are:

  • oci8-connect-entry - initiated by oci_connect(), oci_pconnect() and oci_new_connect(). Fires before database connection is established.
    • char *username - the connection username
    • char *dbname - the database connection string
    • char *charset - the character set specified
    • long session_mode - A binary "or" of OCI_SYSDBA (0x2), OCI_SYSOPER (0x4) and OCI_CRED_EXT (1<<31, or -2147483648 on the platform I was using). Set to 0 by default.
    • int persistent - set to 1 if oci_pconnect() was called, 0 otherwise
    • int exclusive - set to 1 if oci_new_connect() was called, 0 otherwise
  • oci8-connect-return - fires at the end of connection.
    • void *connection - the address of the connection structure
  • oci8-check-connection - initiated if an Oracle error might have caused the connection to become invalid
    • void *connection - the address of the connection structure
    • int is_open - will be 0 if the errcode or server_status indicate the connection is invalid and must be recreated.
    • long errcode - the Oracle error number
    • unsigned long server_status - an indicator from the Oracle library if the connection is considered invalid. If is_open is 0 because errcode indicated the connection was invalid, then server_status will be its default of 1.
  • oci8-sqltext - initiated when oci_parse() is executed
    • void *connection - the address of the connection structure
    • char *sql - text of the SQL statement executed
  • oci8-error - initiated if an Oracle error occurs
    • int status - the Oracle return status of the failing Oracle library call, such as -1 for Oracle's OCI_ERROR or 1 for Oracle's OCI_SUCCESS_WITH_INFO. See Oracle's oci.h for all definitions.
    • long errcode - the Oracle error number
  • oci8-execute-mode - indicates the commit state of an oci_execute() call
    • void *connection - the address of the connection structure
    • unsigned int mode - the mode passed to the Oracle library such as OCI_NO_AUTO_COMMIT (0x00), OCI_DESCRIBE_ONLY (0x10) or OCI_COMMIT_ON_SUCCESS (0x20)

Maintainer probes are below. Refer to the PHP OCI8 source code for the argument descriptions:

  • oci8-connect-p-dtor-close
    • void *connection
  • oci8-connect-p-dtor-release
    • void *connection
  • oci8-connect-lookup
    • void *connection
    • int is_stub
  • oci8-connect-expiry
    • void *connection
    • int is_stub
    • long idle_expiry
    • long timestamp
  • oci8-connect-type
    • int persistent
    • int exclusive
    • void *connection
    • long num_persistent
    • long num_connections
  • oci8-sesspool-create
    • void *session_pool
  • oci8-sesspool-stats
    • unsigned long free
    • unsigned long busy
    • unsigned long open
  • oci8-sesspool-type
    • int type
    • void *session_pool

The PHP OCI8 probes are highly likely to be extended prior to PHP OCI8 2.0 being marked "production". The PHP OCI8 documentation will be updated only at that time, but you can check the oci8_dtrace.d file in the PHP OCI8 source code to see the probe arguments for your version. (Update: The documentation is here).

The probes in PHP OCI8 2.0 replace PHP OCI8 1.4's use of oci_internal_debug() tracing. This function has become a no-op.

Using PHP OCI8 and DTrace

Follow these steps.

  1. Create a simple PHP file, oci8.php, to query the database:

    <?php
    
    error_reporting(0);
    ini_set('display_errors', 'Off');
    
    function do_query($c, $sql)
    {
        $s = oci_parse($c, $sql);
        if (!$s)
            return;
        $r = oci_execute($s);
        if (!$r)
            return;
        while (($row = oci_fetch_row($s)) != false) {
            foreach ($row as $item) {
                echo $item . " ";
            }
            echo "\n";
        }
    }
    
    $c = oci_new_connect('hr', 'welcome', 'localhost/pdborcl');
    
    do_query($c, "select city from locations where rownum < 5 order by 1");
    do_query($c, "select something from does_not_exist");
    
    ?>
  2. Create a D script, user_oci8.d, to probe the execution of oci8.php:

    #!/usr/sbin/dtrace -Zs
    
    php*:::oci8-connect-entry
    {
        printf("PHP connect-entry\n");
        printf("\t   username      %s\n", arg0 ? copyinstr(arg0) : "");
        printf("\t   dbname        %s\n", arg1 ? copyinstr(arg1) : "");
        printf("\t   charset       %s\n", arg2 ? copyinstr(arg2) : "");
        printf("\t   session_mode  %ld\n", (long)arg3);
        printf("\t   persistent    %d\n", (int)arg4);
        printf("\t   exclusive     %d\n", (int)arg5);
    }
    
    php*:::oci8-connect-return
    {
        printf("PHP oci8-connect-return\n");
        printf("\t   connection    0x%p\n", (void *)arg0);
    }
    
    php*:::oci8-connection-close
    {
        printf("PHP oci8-connect-close\n");
        printf("\t   connection    0x%p\n", (void *)arg0);
    }
    
    php*:::oci8-error
    {
        printf("PHP oci8-error\n");
        printf("\t   status        %d\n", (int)arg0);
        printf("\t   errcode       %ld\n", (long)arg1);
    }
    
    php*:::oci8-check-connection
    {
        printf("PHP oci8-check-connection\n");
        printf("\t   connection    0x%p\n", (void *)arg0);
        printf("\t   is_open       %d\n", arg1);
        printf("\t   errcode       %ld\n", (long)arg2);
        printf("\t   server_status %lu\n", (unsigned long)arg3);
    }
    
    php*:::oci8-sqltext
    {
        printf("PHP oci8-sqltext\n");
        printf("\t   connection    0x%p\n", (void *)arg0);
        printf("\t   sql           %s\n", arg0 ? copyinstr(arg1) : "");
    }
    
    php*:::oci8-execute-mode
    {
        printf("PHP oci8-execute-mode\n");
        printf("\t   connection    0x%p\n", (void *)arg0);
        printf("\t   mode          0x%x\n", arg1);
    }
    
  3. As root, start the D script. It will pause, waiting for probes to be fired:

    # chmod +x user_oci8.d
    # ./user_oci8.d

    (Later, this terminal can be Ctrl-C'd when you have finished experimenting with PHP)

  4. Run command-line PHP in another window. The output from the successful query is displayed:

    $ php oci8.php 
    Beijing 
    Bern 
    Bombay 
    Geneva 
    
  5. In the root terminal running the D script, the probes firing during execution of PHP will be displayed:

    # ./user_oci8.d
    dtrace: script 'user_oci8.d' matched 0 probes
    CPU  ID                    FUNCTION:NAME
    1    18 php_oci_do_connect:oci8-connect-entry PHP connect-entry
            username      hr
            dbname        localhost/pdborcl
            charset       
            session_mode  0
            persistent    0
            exclusive     0
    
    0    23 php_oci_do_connect:oci8-connect-return PHP oci8-connect-return
            connection    0x7f64e112cff0
    
    0    31 php_oci_statement_create:oci8-sqltext PHP oci8-sqltext
            connection    0x7f64e112cff0
            sql           select city from locations where rownum < 5 order by 1
    
    0    27 php_oci_statement_execute:oci8-execute-mode PHP oci8-execute-mode
            connection    0x7f64e112cff0
            mode          0x20
    
    0    31 php_oci_statement_create:oci8-sqltext PHP oci8-sqltext
            connection    0x7f64e112cff0
            sql           select something from does_not_exist
    
    0    27 php_oci_statement_execute:oci8-execute-mode PHP oci8-execute-mode
            connection    0x7f64e112cff0
            mode          0x20
    
    0    26 php_oci_error:oci8-error PHP oci8-error
            status        -1
            errcode       942
    
    0    17 php_oci_dtrace_check_connection:oci8-check-connection PHP oci8-check-connection
            connection    0x7f64e112cff0
            is_open       1
            errcode       942
            server_status 1
    
    0    25 php_oci_connection_close:oci8-connection-close PHP oci8-connect-close
             connection    0x7f64e112cff0

    (Adding "-q" to the /usr/sbin/dtrace arguments in user_oci8.d will suppress the CPU and ID details.)

    On multi-CPU machines the probe ordering might not appear sequential, depending on which CPU was processing the probes. Displaying probe timestamps will help reduce confusion, for example:

    php*:::oci8-connect-entry
    {
        printf("PHP connect-entry at %lld\n", walltimestamp);
    }

    From the user_oci8.d DTrace output, you can see

    • The connection being initiated (oci8-connect-entry). The user 'hr' connected to the 'localhost/pdborcl' database. It was an oci_connect() call because both 'exclusive' and 'persistent' were 0. No explicit character set was requested. The default session mode (the optional fifth parameter to oci_connect) was requested.

    • Two SQL statements being parsed (oci8-sqltext) and executed (oci-execute-mode) with mode 0x20 aka OCI_COMMIT_ON_SUCCESS.

    • An Oracle error ORA-942 "table or view does not exist" was generated (oci8-error)

    • The error causing the connection status to be verified (oci8-check-connection). The value of is_open is 1, indicating that the connection is OK.

    With this information you can trace problematic statement execution and connection issues.

Conclusion

This is just a morsel about using DTrace, which is a very powerful utility. Following on from the example above, you could integrate PHP OCI8 tracing with core PHP tracing. Bryan Cantrill posted some examples of core PHP tracing in DTrace and PHP, demonstrated (Note that blog platform upgrades have caused single backslashes to display as double backslashes in his post. Also you no longer need the separate PHP DTrace extension). To explore more DTrace power look on the web for example scripts. There are various blogs too.

Remember that the intent of DTrace is that its functionality is enabled all the time, suitable for development and ready for when you need it most: in production. The design of DTrace means that the probes have zero overhead when nothing is monitoring them.

Finally, as I write this article, I can already see how the PHP OCI8 probes can be enhanced (perhaps to display the connection client identifier to aid end-to-end tracing through the Oracle stack.) Oracle Linux support for DTrace should be improving all the time, too. The power of DTrace on Linux is growing and it's time to think about incorporating it into your application life cycle.

Updated 26 Sep 2013 to mention using an ACL rule for /dev/dtrace/helper

Thursday Jul 25, 2013

Using PHP and Oracle Database 12c Implicit Result Sets

Note: This post describes functionality in PHP OCI8 2.0.0-devel. Functionality and naming is subject to change.

The new Oracle Database 12c "Implicit Result Sets" (IRS) feature allows query results to be returned from a stored PL/SQL procedure (or a PL/SQL anonymous block) without requiring special PHP code. Support for IRS is available in PHP's OCI8 2.0.0-devel extension when it is compiled and used with Oracle Database 12c. (OCI8 2.0 can be compiled and used with other versions of Oracle Database but the available feature set is reduced).

Recall that a normal Oracle query can be performed in PHP with a parse-execute-fetch loop like:

<?php
$c = oci_connect('hr', 'welcome', 'localhost/pdborcl');
$sql = "select city from locations where rownum < 4";
$s = oci_parse($c, $sql);
oci_execute($s);
while (($row = oci_fetch_row($s)) != false) {
    foreach ($row as $item) {
        echo $item . " ";
    }
    echo "\n";
}
?>

The output is:

Beijing
Bern
Bombay

With PHP OCI8 2.0.0-devel and Oracle Database 12c, the same results can be obtained by changing $sql to an anonymous PL/SQL block (or by calling a previously created stored PL/SQL procedure) that uses DBMS_SQL.RETURN_RESULT like:

$sql =
 "declare
    c1 sys_refcursor;
  begin
    open c1 for select city from locations where rownum < 4;
    dbms_sql.return_result(c1);
  end;";

With this statement change, the previous PHP code fetches the query results without needing any logic alterations. In older versions without IRS, the PL/SQL and PHP code would have to handle a REF CURSOR parameter.

The real fun begins when you have multiple DBMS_SQL.RETURN_RESULT calls in the same PL/SQL block:

$sql =
 "declare
    c1 sys_refcursor;
  begin
    open c1 for select city from locations where rownum < 4;
    dbms_sql.return_result(c1);
    open c1 for select first_name, last_name from employees where rownum < 4;
    dbms_sql.return_result(c1);
  end;";

The PHP fetch loop handles this nicely and sequentially fetches rows from both queries:

Beijing  
Bern  
Bombay  
Ellen Abel  
Sundar Ande  
Mozhe Atkinson  

Only oci_fetch_array(), oci_fetch_assoc(), oci_fetch_object() and oci_fetch_row() (but not oci_fetch() or oci_fetch_all()) will automatically fetch IRS data like this. [This is a semi-arbitrary decision trying to balance the increased amount of code complexity and testing versus the expected use of the feature. If there is strong demand this decision can be revisited.]

To process each of the query results independently in PHP, use the newly introduced oci_get_implicit_resultset() function. This takes the parent statement resource, e.g. $s, and returns a PHP statement resource corresponding to the first result set. Each time oci_get_implicit_resultset() is subsequently called, it returns the next result set. When there are no more result sets, it returns false. Because oci_get_implicit_resultset() returns a statement resource, you can use any of the oci_fetch_* functions to get rows.

For example, to print appropriate column names above each row's items:

<?php
$c = oci_connect('hr', 'welcome', 'localhost/pdborcl');
$sql =
 "declare
    c1 sys_refcursor;
  begin
    open c1 for select city from locations where rownum < 4;
    dbms_sql.return_result(c1);
    open c1 for select first_name, last_name from employees where rownum < 4;
    dbms_sql.return_result(c1);
  end;";
$s = oci_parse($c, $sql);
oci_execute($s);
while (($s2 = oci_get_implicit_resultset($s))) {
    // Now treat $s2 as a distinct query statement resource
    $ncols = oci_num_fields($s2);
    for ($i = 1; $i <= $ncols; ++$i) {
        $colname = oci_field_name($s2, $i);
        echo $colname . " ";
    }
    echo "\n";
    while (($row = oci_fetch_row($s2)) != false) {
        foreach ($row as $item) {
            echo $item . " ";
        }
        echo "\n";
    }
}
?>

The output is:

CITY  
Beijing  
Bern  
Bombay  
FIRST_NAME LAST_NAME  
Ellen Abel  
Sundar Ande  
Mozhe Atkinson  

You can also do things like calling oci_set_prefetch() on the IRS statement resources, or calling oci_get_implicit_resultset() multiple times before beginning to fetch row data:

$sql =
 "declare
    c1 sys_refcursor;
  begin
    open c1 for select city from locations where rownum < 4;
    dbms_sql.return_result(c1);
    open c1 for select first_name, last_name from employees where rownum < 4;
    dbms_sql.return_result(c1);
  end;";
$s = oci_parse($c, $sql);
oci_execute($s);
$s1 = oci_get_implicit_resultset($s);
$s2 = oci_get_implicit_resultset($s);
$row1_1 = oci_fetch_row($s1);
$row2_1 = oci_fetch_row($s2);
$row1_2 = oci_fetch_row($s1);
$row2_2 = oci_fetch_row($s2);
. . .

There are more examples in the OCI8 test suite (see the tests sub-directory of the source bundle).

When would you used an IRS? Some cases are:

  • Migrating an application to Oracle Database, where the application currently makes use of stored procedures returning result sets. The IRS support in OCI8 will make migration easier.
  • Instead of calling a PL/SQL procedure and then executing a separate SELECT in PHP, complex processing can be performed in a stored PL/SQL procedure before that procedure returns results to PHP. This architecture might help system scalability since it reduces the number of calls made to the database.
  • PHP Frameworks typically use a basic oci_fetch_* call, so they will will automatically be able fetch IRS results.

I can't suggest turning every individual SELECT statement into an IRS since this will add the overhead of the PL/SQL-to-SQL calls. However there are legitimate use cases for Implicit Result Sets that open some interesting possibilities.

PHP OCI8 2.0.0-devel for Oracle Database is on PECL

PHP OCI8 2.0.0-devel is now available on PECL (and in the PHP 'master' branch). This is a development release, so changes may occur. I'm looking for feedback, particularly on:

  • Feature design, including naming choices
  • Install feedback from different platforms with different build tool versions
  • Whether to drop support for installing on PHP 4. I'm likely to do this. (The OCI8 1.4.10 release is usable for installing on PHP 4)

OCI8 2.0 can be installed as a shared extension from PECL with:

pecl install oci8-devel

Alternatively, if you have OCI8 1.x currently installed as a static extension, then you will need to build PHP again. This is easy using a trunk snapshot from snaps.php.net. Instructions for building are in various places on the web, including in The Underground PHP and Oracle Manual.

The OCI8 2.0.0-devel release contains a bunch of clean ups, and some new and changed features. The full list is found in the package.xml file:

    - NEW FUNCTIONALITY:
 
      - Added Implicit Result Set support for Oracle Database 12c.
	Streaming of all IRS's returned from a PL/SQL block is available
	via oci_fetch_array, oci_fetch_assoc, oci_fetch_object and
	oci_fetch_row (but not oci_fetch or oci_fetch_all).
	Alternatively individual IRS statement resources can be obtained
	with the new function 'oci_get_implicit_resultset' and passed to
	any oci_fetch_* function.

      - Added DTrace probes enabled with PHP's generic --enable-dtrace

    - IMPROVED FUNCTIONALITY:
 
      - Using 'oci_execute($s, OCI_NO_AUTO_COMMIT)' for a SELECT no
	longer unnecessarily initiates an internal ROLLBACK during
	connection close.  This can improve overall scalability by
	reducing "round trips" between PHP and the database.
 
    - CHANGED FUNCTIONALITY:
 
      - PHPINFO() CHANGES:
 
        - The oci8.event and oci8.connection_class values are now shown
          only when the Oracle client libraries support the respective
          functionality.
 
        - Connection statistics are now in a separate phpinfo() table.
 
        - Temporary LOB and Collection support status lines in
          phpinfo() were removed.  These features have always been
          enabled since 2007.
 
      - OCI_INTERNAL_DEBUG() CHANGES:
 
        - The oci_internal_debug() function is now a no-op.  Use PHP's
          --enable-dtrace functionality with DTrace or SystemTap instead.
 
    - INTERNAL CHANGES:
 
      - Fixed a potential NULL pointer dereference flagged by Parfait
        static code analysis.
 
      - Extended testing of existing OCI8 functionality.
 
      - Improved test output portability when using the PHP development
        web server to run tests.
 
      - Removed no-longer necessary Unicode patterns from tests
        (vestiges of PHP's previous PHP 6 project)
        
      - Improved build portability by removing compilation type cast
        warnings with some compilers.
 
      - Fixed compilation warnings when building with Oracle 9.2
        client libraries.
 
      - Updated code to use internal macro PHP_OCI_REGISTER_RESOURCE.
 
      - Regularized code prototypes and fixed some in-line documentation
        prototypes.
 
      - Fixed code folding. 

Subsequent blog posts will talk about the features in OCI8 2.0.0.

Thursday May 16, 2013

Offline Processing in PHP with Advanced Queuing

Offloading slow batch tasks to an external process is a common method of improving website responsiveness. One great way to initiate such background tasks in PHP is to use Oracle Streams Advanced Queuing in a producer-consumer message passing fashion. Oracle AQ is highly configurable. Messages can queued by multiple producers. Different consumers can filter messages. From PHP, the PL/SQL interface to AQ is used. There are also Java, C and HTTPS interfaces, allowing wide architectural freedom. Oracle Advanced Queuing is included in all editions of the database.

The following example simulates an application user registration system where the PHP application queues each new user's street address. An external system monitoring the queue can then fetch and process that address. In real life the external system might initiate a snail-mail welcome letter, or do further, slower automated validation on the address.

The following SQL*Plus script qcreate.sql creates a new Oracle user demoqueue with permission to create and use queues. A payload type for the address is created and a queue is set up for this payload.

-- qcreate.sql

connect / as sysdba
drop user demoqueue cascade;

create user demoqueue identified by welcome;
grant connect, resource to demoqueue;
grant aq_administrator_role, aq_user_role to demoqueue;
grant execute on dbms_aq to demoqueue;
grant create type to demoqueue;

connect demoqueue/welcome@localhost/orcl

-- The data we want to queue
create or replace type user_address_type as object (
  name        varchar2(10),
  address     varchar2(50)
);
/

-- Create and start the queue
begin
 dbms_aqadm.create_queue_table(
   queue_table        =>  'demoqueue.addr_queue_tab',
   queue_payload_type =>  'demoqueue.user_address_type');
end;
/

begin
 dbms_aqadm.create_queue(
   queue_name         =>  'demoqueue.addr_queue',
   queue_table        =>  'demoqueue.addr_queue_tab');
end;
/

begin
 dbms_aqadm.start_queue(
   queue_name         => 'demoqueue.addr_queue',
   enqueue            => true);
end;
/

The script qhelper.sql creates two useful helper functions to enqueue and dequeue messages:

-- qhelper.sql
-- Helpful address enqueue/dequeue procedures

connect demoqueue/welcome@localhost/orcl

-- Put an address in the queue
create or replace procedure my_enq(name_p in varchar2, address_p in varchar2) as
  user_address       user_address_type;
  enqueue_options    dbms_aq.enqueue_options_t;
  message_properties dbms_aq.message_properties_t;
  enq_id             raw(16);
begin
  user_address := user_address_type(name_p, address_p);
  dbms_aq.enqueue(queue_name         => 'demoqueue.addr_queue',
                  enqueue_options    => enqueue_options,
                  message_properties => message_properties,
                  payload            => user_address,
                  msgid              => enq_id);
  commit;
end;
/
show errors

-- Get an address from the queue
create or replace procedure my_deq(name_p out varchar2, address_p out varchar2) as
  dequeue_options    dbms_aq.dequeue_options_t;
  message_properties dbms_aq.message_properties_t;
  user_address       user_address_type;
  enq_id             raw(16);
begin
  dbms_aq.dequeue(queue_name         => 'demoqueue.addr_queue',
                  dequeue_options    => dequeue_options,
                  message_properties => message_properties,
                  payload            => user_address,
                  msgid              => enq_id);
  name_p    := user_address.name;
  address_p := user_address.address;
  commit;
end;
/
show errors

The script newuser.php is the part of the PHP application that handles site registration for a new user. It queues a message containing their address and continues executing:

<?php
// newuser.php

$c = oci_connect("demoqueue", "welcome", "localhost/orcl");

// The new user details
$username = 'Fred';
$address  = '500 Oracle Parkway';

// Enqueue the address for later offline handling
$s = oci_parse($c, "begin my_enq(:username, :address); end;");
oci_bind_by_name($s, ":username", $username, 10);
oci_bind_by_name($s, ":address",  $address,  50);
$r = oci_execute($s);

// Continue executing
echo "Welcome $username\n";

?>

It executes an anonymous PL/SQL block to create and enqueue the address message. The immediate script output is simply the echoed welcome message:

Welcome Fred

Once this PHP script is executed, any application can dequeue the new message at its leisure. For example, the following SQL*Plus commands call the helper my_deq() dequeue function and displays the user details:

-- getuser.sql

connect demoqueue/welcome@localhost/orcl

set serveroutput on
declare
  name varchar2(10);
  address varchar2(50);
begin
  my_deq(name, address);
  dbms_output.put_line('Name     : ' || name);
  dbms_output.put_line('Address  : ' || address);
end;
/

The output is:

Name     : Fred
Address  : 500 Oracle Parkway

If you instead want to check the queue from PHP, use getuser.php:

<?php
// getuser.php

$c = oci_connect("demoqueue", "welcome", "localhost/orcl");

// dequeue the message
$sql = "begin my_deq(:username, :address); end;";
$s = oci_parse($c, $sql);
oci_bind_by_name($s, ":username", $username, 10);
oci_bind_by_name($s, ":address", $address, 50);
$r = oci_execute($s);

echo "Name     : $username\n";
echo "Address  : $address\n";

?>

If the dequeue operation is called without anything in the queue, it will block waiting for a message until the queue wait time expires. This is configurable by setting a zero wait time dequeue_options.wait := 0; before calling dbms_aq.dequeue.

The PL/SQL API has much more functionality than shown in this overview. For example you can enqueue an array of messages, or listen to more than one queue. Queuing is highly configurable and scalable, providing a great way to distribute workload for web or mobile applications. More information about AQ is in the Oracle Streams Advanced Queuing User's Guide.

Bootnote: The basis for this blog post comes from the Underground PHP and Oracle Manual

This post was updated to show setting a zero wait time.

Thursday Mar 21, 2013

Python cx_Oracle and Oracle 11g DRCP Connection Pooling

The topic of Oracle 11g DRCP connection pooling in Python cx_Oracle came up twice this week for me. DRCP is a database tier connection pooling solution which is great for applications run in multiple processes. There is a whitepaper on DRCP that covers a lot of background and talks about configuration. This whitepaper is ostensibly about PHP but is good reading for all DRCP users.

The first DRCP and cx_Oracle scenario I dealt with was a question about mod_python.

To cut a long story short, I created a handler and requested it 1000 times via Apache's 'ab' tool. In my first script, and despite having increased the default pool parameters, there were a high number of NUM_WAITS. Also NUM_AUTHENTICATIONS was high. Performance wasn't the best. Querying V$CPOOL_CC_STATS showed:

CCLASS_NAME  NUM_REQUESTS   NUM_HITS NUM_MISSES  NUM_WAITS NUM_AUTHENTICATIONS
------------ ------------ ---------- ---------- ---------- -------------------
HR.CJDEMO1           1000        992          8        478                1000

At least the session information in each DRCP server was reused (shown via a high NUM_HITS).

Results were better after fixing the script to look like:

from mod_python import apache
import cx_Oracle
import datetime

# Example: Oracle 11g DRCP with cx_Oracle and mod_python

# These pool params are suitable for Apache Pre-fork MPM
mypool = cx_Oracle.SessionPool(user='hr', password='welcome',
         dsn='localhost/orcl:pooled', min=1, max=2, increment=1)

def handler(req):
    global mypool

    req.content_type = 'text/html'
    n = datetime.datetime.now()
    req.write (str(n) + "<br>");

    db = cx_Oracle.connect(user='hr', password='welcome',
            dsn='localhost/orcl:pooled', pool=mypool, cclass="CJDEMO1",
            purity=cx_Oracle.ATTR_PURITY_SELF)

    cur = db.cursor()
    cur.execute('select * from locations')
    resultset = cur.fetchall()
    for result in resultset:
        for item in result:
            req.write (str(item) + " ")
        req.write ("<br>")
    cur.close()
    mypool.release(db)

    return apache.OK

The 'ab' benchmark on this script ran much faster and the stats from V$CPOOL_CC_STATS looked much better. The number of authentications was right down about to about 1 per Apache (ie. mod_python) process:

CCLASS_NAME  NUM_REQUESTS   NUM_HITS NUM_MISSES  NUM_WAITS NUM_AUTHENTICATIONS
------------ ------------ ---------- ---------- ---------- -------------------
HR.CJDEMO1           1000        977         23         13                  26

The NUM_HITS was high again, because the DRCP purity was ATTR_PURITY_SELF. If I hadn't wanted session information to be reused each time the handler was executed, I could have set the purity to ATTR_PURITY_NEW. If I'd done this then NUM_HITS would have been low and NUM_MISSES would have been high.

If you're testing this yourself, before restarting the DRCP pool don't forget to shutdown Apache to close all DB connections. Otherwise restarting the pool will block. Also, if you're interpreting your own V$CPOOL_CC_STATS stats don't forget to account for the DRCP "dedicated optimization" that retains an association between clients (mod_python processes) and the DB. The whitepaper previously mentioned discusses this.

The second place where DRCP and python came up this week was on the cx_Oracle mail list. David Stanek posed a question. He was seeing application processes blocking while waiting for a DRCP pooled server to execute a query. My variant of David's script is:

import os
import time
import cx_Oracle

# Example: Sub-optimal connection pooling with Oracle 11g DRCP and cx_Oracle

def do_connection():
    print 'Starting do_connection ' + str(os.getpid())
    con = cx_Oracle.connect(user=user, password=pw, dsn=dsn, cclass="CJDEMO2",
           purity=cx_Oracle.ATTR_PURITY_SELF)
    cur = con.cursor()
    print 'Querying ' + str(os.getpid())
    cur.execute("select to_char(systimestamp) from dual")
    print cur.fetchall()
    cur.close()
    con.close()
    print 'Sleeping ' + str(os.getpid())
    time.sleep(30)
    print 'Finishing do_connection ' + str(os.getpid())
 
user = 'hr'
pw = 'welcome'
dsn = 'localhost/orcl:pooled'
for x in range(100):
    pid = os.fork()
    if not pid:
        do_connection()
        os._exit(0)

This script forks off a bunch of processes - more than the number of pooled DRCP servers (see MAXSIZE in the DBA_CPOOL_INFO view). The first few processes grab a DRCP server from the pool and do their query. But they don't release the DRCP server back to the DRCP pool until after the sleep() when the process ends. The other forked processes are blocked waiting for those DRCP servers to become available. This isn't optimal pool sharing.

My suggestion was to use an explicit cx_Oracle session pool like this:

import os
import time
import cx_Oracle

# Example: Connection pooling with Oracle 11g DRCP and cx_Oracle
 
def do_connection():
    print 'Starting do_connection ' + str(os.getpid())
    mypool = cx_Oracle.SessionPool(user=user,password=pw,dsn=dsn,min=1,max=2,increment=1)
    con = cx_Oracle.connect(user=user, password=pw,
          dsn=dsn, pool = mypool, cclass="CJDEMO3", purity=cx_Oracle.ATTR_PURITY_SELF)
    cur = con.cursor()
    print 'Querying ' + str(os.getpid())
    cur.execute("select to_char(systimestamp) from dual")
    print cur.fetchall()
    cur.close()
    mypool.release(con)
    print 'Sleeping ' + str(os.getpid())
    time.sleep(30)
    print 'Finishing do_connection ' + str(os.getpid())

user = 'hr'
pw = 'welcome'
dsn = 'localhost/orcl:pooled'
for x in range(100):
    pid = os.fork()
    if not pid:
        do_connection()
        os._exit(0)

The mypool.release(con) call releases the DRCP server back to the DRCP pool prior to the sleep. When this second script is run, there is a smoothness to the output. The queries happen sequentially without noticeably being blocked.

Like with any shared resource, it is recommended to release DRCP pooled servers back to the pool when they are no longer needed by the application.

Tuesday Dec 11, 2012

Excitement! Updated Underground PHP and Oracle Manual is Available for Download

We're thrilled to have a major update of the free Underground PHP and Oracle Manual released on OTN.

The Underground PHP and Oracle Manual is designed to bridge the gap between the many PHP scripting language and the many Oracle Database books available. It contains unique material about PHP's OCI8 extension for Oracle Database, and about other components in the PHP-Oracle ecosystem. It shows PHP developers how to use PHP and Oracle together, efficiently and easily.

The book has been completely refreshed. It has been updated for Oracle XE 11g and the latest PHP OCI8 extension. There are new chapters about using PHP with Oracle TimesTen, NetBeans and Oracle Tuxedo. There is also a new chapter about installing PHP on Oracle Solaris. The book now clocks in at 347 pages of great content.

Acknowledgements are due to all those who have helped with this and previous editions of the book. Thanks to the product teams that assisted with brand new content. In particular Craig Mohrman contributed the chapter about PHP on Solaris. Jeffry Rubinoff contributed the base text for the chapter on PHP and NetBeans.

Thursday Jan 19, 2012

PHP VirtualBox VM has been refreshed

While I was recently on summer vacation (yes, it is summer in half the world), the VirtualBox VM for PHP was refreshed to a more recent Zend Server/Oracle Linux/Oracle Database XE stack.

I just pulled the VM down, imported it and had it booting and serving PHP pages in a very few minutes. VirtualBox really is marvelous. There is a link to download the VM near the foot of the Oracle Technology Network Developer VM page.

Saturday Sep 03, 2011

Oracle 11.2 XE with newly updated PHP Developer's Guide is available

Oracle Database 11g Release 2 Express Edition aka "Oracle XE" is now available on Linux 64 bit and Windows 32 bit. This is a free version of the Oracle Database. Windows 64 bit is "in the works" but Linux 32 bit is not planned.

Check out the newly updated Oracle Database Express Edition 2 Day + PHP Developer's Guide. As well as HTML and PDF variants, the manual is available in Mobi and EPUB formats.

The 2 Day + PHP manual has steps for installing PHP and walks through creating an introductory application. It shows different ways to interact with Oracle XE and introduces PHP 5.3 features.

The example shows the mechanics of DB interaction. It builds the application from the ground up so you can understand how to construct your own high performance applications. If you want to continue the learning path and use a PHP framework, Oracle 11g XE works with the Developing a PHP Web Application with Oracle Database 11g training.

The Oracle 11.2 XE Linux install is RPM based. It takes just a few minutes to install, prompting only for a few necessary details such as desired passwords and ports. You need root access to install it.

Oracle 11.2 XE supports DRCP connection pooling so you'll really be able to maximize the small footprint database for PHP applications.

Readers who want to dive deeper into detail about PHP and advanced features available in other editions of Oracle Database might be interested in the later sections of the Underground PHP and Oracle Manual.

Wednesday Jun 15, 2011

Oracle Resources for PHP

Here are some key resources for working with PHP and Oracle technologies.

  • Overall Links

    Oracle : Oracle Technology Network (OTN)

    Homepage : The PHP Developer Center -- downloads, how-tos, sample code and discussion forums brought to you by OTN.

    Read : PHP Articles -- a collection of informative articles on OTN.

    Technology : Download the newest versions of other software in Oracle's Technology Stack. Read about other Oracle application development tools.

  • PHP Oracle Database Extension : OCI8 is the most available and scalable PHP adapter for the Oracle database. It is included with PHP, and is also separately downloadable for upgrading older PHP releases. OCI8 works with PHP 4 and PHP 5, and will compile with Oracle 9iR2, 10g and 11g client libraries. Oracle's standard cross-version compatibility and connectivity is applicable, so OCI8 can connect to older or newer databases, locally or remotely. The latest OCI8 release includes support for Oracle Database 11g Database Resident Connection Pooling (DRCP), and for Fast Application Notification (FAN) [whitepaper here], and also has support for Oracle's authentication and end-to-end tracing meta data attributes [article here]. These features improve scalability and availabilty of the OCI8 extension.

    The OCI8 extension can also be used with the Oracle In-Memory Database Cache.

    Book : The Underground PHP & Oracle Manual -- the definitive, free guide to using PHP with Oracle Database.

    Tutorial : Oracle & PHP tutorials -- step by step Oracle Learning Library tutorials for using PHP with Oracle. (Free OTN login required)

    Read : PHP & High Scalability -- covers enabling DRCP and FAN for PHP applications.

    Read : PHP Web Auditing, Authorization and Monitoring with Oracle Database -- learn how to audit individual web users, automatically apply rules to individual web users to restrict data access, and monitor and trace database usage per application user.

    Forum : The Oracle & PHP forum -- technical discussion forum for using PHP with Oracle.

    Blog : PHP and Oracle: Christopher Jones -- The latest news on PHP and Oracle.

  • Database : Oracle Express Edition Database -- an entry-level, small-footprint database based on the standard Oracle Database code base that's free to develop, deploy, and distribute; fast to download; and simple to administer.

    PHP OCI8 works with Oracle Database XE the same way it works with the other editions of Oracle Database.

    Oracle Database XE is a great starter database for:

    • Developers working on PHP, Python, Ruby, Java, .Net and other open source applications.
    • DBAs who need a free, starter database for training and deployment
    • Independent Software Vendors (ISVs) and hardware vendors who want a starter database to distribute free of charge
    • Educational institutions and students who need a free database for their curriculum

    Install Now!

  • Database : MySQL -- The world's most popular open source database. MySQL Community Edition is the freely downloadable version. Commercial customers have the flexibility of choosing from multiple editions to meet specific business and technical requirements. Also available for free is the MySQL Workbench for SQL Authoring, System Administration, and schema modeling.

    Recent additions to MySQL include semi synchronous replication, direct memcached-to-InnoDB access, multi-threaded replication, and enhanced partitioning. See What's new in MySQL 5.6

    PHP's mysqli or PDO_mysql extensions can be used to access MySQL.

    Check out the new Query Cache plugin documented here and the Replication and Load-Balancing plugin for master-slave-splitting, documented [here].

    Homepage : Using MySQL With PHP -- Articles and downloads

    Forum : PHP and MySQL forum -- The place to ask questions

    Blog : Planet MySQL -- The latest MySQL news from the community

    Blog : Johannes Schl├╝ter -- A member of the MySQL connector team and the current PHP Release Master.

    Blog : Me Talking Out Loud -- Ligaya Turmelle, a member of MySQL Support. (and contributer to The PHP Anthology: 101 Essential Tips, Tricks & Hacks)

    Blog : Internet Super Hero -- Ulf Wendel, a member of the MySQL connector team.

    Books : Many! Including PHP and MySQL Web Development and Web Database Applications with PHP & MySQL and Learning PHP & MySQL: Step-by-Step Guide to Creating Database-Driven Web Sites

    Install Now!

  • Database : Oracle Berkeley DB 11g -- provides the complex data management features found in enterprise class databases. These facilities include high throughput, low-latency reads, non-blocking writes, high concurrency, data scalability, in-memory caching, ACID transactions, automatic and catastrophic recovery when the application, system or hardware fails, high availability and replication in an application configurable package. Simply configure the library and use the particular features available to satisfy your particular application needs. Berkeley DB can be configured to address any application need from the hand-held device to the datacenter, from a local storage solution to a world-wide distributed one, from kilobytes to petabytes.

    Berkeley DB's SQL API allows PHP's sqlite3 and PDO_sqlite extensions to be used.

    Berkeley DB also includes source code for a php_db4 extension.

    Install Now!

  • IDE : NetBeans -- lets you develop desktop, mobile and web applications using Java, PHP, C/C++ and more. Runs on Windows, Linux, Mac OS X and Solaris. NetBeans IDE is open-source and free.

    Understand: NetBeans PHP features -- All the great features that NetBeans has for PHP developers

    Learn: NetBeans PHP Learning Trail -- the best way to learn how to use NetBeans

    Install Now!

  • Virtualize : Oracle VM VirtualBox -- powerful Cross-platform Virtualization Software for x86-based systems. "Cross-platform" means that it installs on Windows, Linux, Mac OS X and Solaris x86 computers. And "Virtualization Software" means that you can create and run multiple Virtual Machines, running different operating systems, on the same computer at the same time. For example, you can run Windows and Linux on your Mac, run Linux and Solaris on your Windows PC, or run Windows on your Linux systems.

    Oracle VM VirtualBox is available as Open Source or pre-built Binaries for Windows, Linux, Mac OS X and Solaris.

    OTN hosts some pre-built Developer VMs , including an Oracle Tuxedo Web Application Server VM showing PHP support. There is also a Zend Server VM for PHP created by Zend. Zend Server is a complete, Oracle-enabled, enterprise-ready Web Application Server for running and managing PHP applications that require a high level of reliability, performance and security. Zend Server is available in community and supported editions.

    Install Now!

  • Operating system : Oracle Linux -- free to download and distribute. As one of the most widely deployed operating systems today, Linux is increasingly being adopted for cloud-based solutions. Oracle Linux is the most complete and integrated solution available and delivers higher performance and better reliability at up to 7 times lower cost than Red Hat. Why Choose Oracle Linux over Red Hat Linux?

    Oracle Linux 5.6 and 6 introduced PHP 5.3 packages. Subscribers to the Unbreakable Linux Network have access to an additional pre-built PHP OCI8 RPM, and also direct access to an RPM for installing Zend Server .

    Users of older Linux 5 releases can get PHP 5.3 RPMs from oss.oracle.com .

    Install Now!

  • Application Server : Oracle Tuxedo -- provides a robust, grid enabled platform for developing enterprise applications. It provides mainframe-class scale and performance on open, distributed systems for software written in C, C++, COBOL, PHP, Python and Ruby. Oracle Tuxedo provides cost-effective reliability, extreme scalability and throughput of hundreds of thousands of transactions per second. Functionality like Web services, SCA programming model, metadata driven application development make it simple to develop and integrate applications written in many programming languages.

    PHP applications can be hosted on the Tuxedo platform without requiring any code changes and can leverage high availability, scalability and integration capabilities.

    The whitepaper Oracle Tuxedo - An Enterprise Platform for Dynamic Languages explains the architecture and features. A Tuxedo Demo VM for VirtualBox is available for immediate testing.

    Install Now!

  • Client Libraries : Oracle Instant Client -- a small footprint set of libraries that allows applications and tools to connect to an existing Oracle Database. Oracle OCI, OCCI, Pro*C, ODBC, and JDBC applications work without modification.

    The PHP OCI8 extension can be built with Oracle Instant Client to connect to a remote database.

    Instant Client is provided under a separate OTN Development and Distribution License for Instant Client that allows most licensees to download, redistribute, and deploy in production environments, without charge.

    Install Now!

Friday Apr 01, 2011

Oracle 11gR2 XE Beta is now available

[Read More]
About

Tourists looking out over an Opal mine
I'm a Product Manager in Server Technologies, working on scripting languages and developer-access.
Email: christopher.jones@oracle.com
Twitter: http://twitter.com/ghrd
Book: Free PHP Oracle book
Download: PHP Linux RPMs with the OCI8 extension
Links: OTN PHP Developer Center

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today