Skip to content

oci8.php fetchInto() always returns the rows in OCI_ASSOC order independent of the value of fetchmode passed in to the function. #50

@navistartronic

Description

@navistartronic

oci8.php, function fetchInto(), lines 385 and 397:

         function fetchInto($result, &$arr, $fetchmode, $rownum = null)
         {
             if ($rownum !== null) {
                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
             }
             if ($fetchmode & DB_FETCHMODE_ASSOC) {
(385)            $arr = @oci_fetch_array($result,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
                 if (is_array($arr)) {
                     $moredata = count($arr);
                 } else {
                     $moredata = false;
                 }
                 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE &&
                     $moredata)
                 {
                     $arr = array_change_key_case($arr, CASE_LOWER);
                 }
             } else {
(397)            $arr = @oci_fetch_array($result,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);  <= s/b OCI_NUM

oci_fetch_array() is always called with OCI_ASSOC value and you cannot change it. It is written with assumption that you always want it returned in OCI_ASSOC order.

arg fetchmode can be any one of :

  • DB_FETCHMODE_DEFAULT
  • DB_FETCHMODE_ORDERED
  • DB_FETCHMODE_ASSOC
  • DB_FETCHMODE_OBJECT
  • DB_FETCHMODE_FLIPPED

Valid modes in oci_fetch_array () used in the if-else can only be

  • OCI_BOTH
  • OCI_ASSOC
  • OCI_NUM

When the expression "if ($fetchmode & DB_FETCHMODE_ASSOC) " evaluates to true,
(385) $arr = @oci_fetch_array($result,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
DB_FETCHMODE_ASSOC is hard coded and mapped (or implied) into OCI_ASSOC which works and is correct.

But when "if ($fetchmode & DB_FETCHMODE_ASSOC)" evaluates to false,
independently of what value $fetchmode is, OCI_ASSOC is always used as the value in oci_fetch_array():
(397) $arr = @oci_fetch_array($result,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);

The problem lies in the else block when the expression is false.
$fetchMode can be potentially any 1 of the 5 DB_FETCHMODE_* values, while there are only 3 OCI_* values to specify in oci_fetch_array().

Technically there should be a mapping of $fetchMode => OCI_*

  • DB_FETCHMODE_DEFAULT => ?
  • DB_FETCHMODE_ORDERED => OCI_NUM
  • DB_FETCHMODE_ASSOC => OCI_ASSOC
  • DB_FETCHMODE_OBJECT => ?
  • DB_FETCHMODE_FLIPPED => ?

As it is written, the rows are always returned in OCI_ASSOC order in the else block.

I found this out when an application I took over calls fetchInto() using both DB_FETCHMODE_ASSOC and DB_FETCHMODE_ORDERED and the resultant rows being returns was alway in OCI_ASSOC order throwing exceptions.

In my specific situation I modified the else block line at 397 oci_fetch_array() to always use OCI_NUM and it solved my specific problem.

This is the diff between the original and my problem fixed using OCI_NUM in the else block.

# diff oci8.php-dist oci8.php
397c397
<             $arr = @oci_fetch_array($result,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
---
>             $arr = @oci_fetch_array($result,OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS);

I have tested this in my own application and this fixed the problem.

Sorry but I do no have any suggestions as to what a proper "fix" would be in this case. Hmmm.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions