Author: timbo
Date: Wed Feb 21 17:44:25 2007
New Revision: 9152

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/lib/DBD/Gofer.pm
   dbi/trunk/lib/DBD/Gofer/Policy/rush.pm
   dbi/trunk/lib/DBI/DBD.pm
   dbi/trunk/lib/DBI/Gofer/Execute.pm
   dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm
   dbi/trunk/t/12quote.t

Log:
Make dbi_dumpcom more robust, also show Name or Statement if possible.
Change dbih_setup_fbav to be able to adjust the row buffer size properly.
Change STORE of NUM_OF_FIELDS to call dbih_setup_fbav if required.
No longer auto adjust DBIc_NUM_FIELDS if inconsistent when a row is fetched.
Note more caveats in DBD:Gofer docs.
Add hack mechanism in Gofer/Execute.pm to return updated dbh attr after an sth 
method call
(specifically for $dbh->{mysql_insertid})
Add more_results method docs to DBI::DBD.
Updated column_info docs to note that if a table doesn't exist you get an sth 
for an empty result set and not an error


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Wed Feb 21 17:44:25 2007
@@ -51,8 +51,13 @@
   Changed handle factory methods, like connect, prepare, and table_info,
     to copy any error/warn/info state of the handle being returned
     up into the handle the method was called on.
+  Changed row buffer handling to not alter NUM_OF_FIELDS if it's
+    inconsistent with number of elements in row buffer array.
+  Updated DBI::DBD docs re handling multiple result sets.
   Updated DBI::DBD docs for driver authors thanks to Ammon Riley
     and Dean Arnold.
+  Updated column_info docs to note that if a table doesn't exist
+    you get an sth for an empty result set and not an error.
 
   Added new DBD::Gofer 'stateless proxy' driver and framework,
     and the DBI test suite is now also executed via DBD::Gofer,

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Wed Feb 21 17:44:25 2007
@@ -4439,6 +4439,8 @@
   $sth = $dbh->table_info( $catalog, $schema, $table, $type );
   $sth = $dbh->table_info( $catalog, $schema, $table, $type, \%attr );
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Returns an active statement handle that can be used to fetch
 information about tables and views that exist in the database.
 
@@ -4515,6 +4517,8 @@
 
   $sth = $dbh->column_info( $catalog, $schema, $table, $column );
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Returns an active statement handle that can be used to fetch
 information about columns in specified tables.
 
@@ -4525,6 +4529,9 @@
 driver doesn't support one or more of them then you may get back more
 than you asked for and can do the filtering yourself.
 
+If the arguments don't match any tables then you'll still get a statement
+handle, it'll just return no rows.
+
 The statement handle returned has at least the following fields in the
 order shown below. Other fields, after these, may also be present.
 
@@ -4627,15 +4634,12 @@
 
   $sth = $dbh->primary_key_info( $catalog, $schema, $table );
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Returns an active statement handle that can be used to fetch information
 about columns that make up the primary key for a table.
 The arguments don't accept search patterns (unlike table_info()).
 
-For example:
-
-  $sth = $dbh->primary_key_info( undef, $user, 'foo' );
-  $data = $sth->fetchall_arrayref;
-
 The statement handle will return one row per column, ordered by
 TABLE_CAT, TABLE_SCHEM, TABLE_NAME, and KEY_SEQ.
 If there is no primary key then the statement handle will fetch no rows.
@@ -4686,6 +4690,8 @@
                                , $fk_catalog, $fk_schema, $fk_table
                                , \%attr );
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Returns an active statement handle that can be used to fetch information
 about foreign keys in and/or referencing the specified table(s).
 The arguments don't accept search patterns (unlike table_info()).
@@ -4713,6 +4719,8 @@
   $sth = $dbh->foreign_key_info( undef, undef,   undef , undef, $user, 
'detail');
   $sth = $dbh->foreign_key_info( undef, $user, 'master', undef, $user, 
'detail');
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Note: The support for the selection criteria, such as C<$catalog>, is
 driver specific.  If the driver doesn't support catalogs and/or
 schemas, it may ignore these criteria.
@@ -4801,6 +4809,8 @@
 
   $sth = $dbh->statistics_info( $catalog, $schema, $table, $unique_only, 
$quick );
 
+  # then $sth->fetchall_arrayref or $sth->fetchall_hashref etc
+
 Returns an active statement handle that can be used to fetch statistical
 information about a table and its indexes.
 
@@ -4814,11 +4824,6 @@
 available from the server, and might not be current.  Some databases may
 return stale statistics or no statistics at all with this flag set.
 
-For example:
-
-  $sth = $dbh->statistics_info( undef, $user, 'foo', 1, 1 );
-  $data = $sth->fetchall_arrayref;
-
 The statement handle will return at most one row per column name per index,
 plus at most one row for the entire table itself, ordered by NON_UNIQUE, TYPE,
 INDEX_QUALIFIER, INDEX_NAME, and ORDINAL_POSITION.

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Wed Feb 21 17:44:25 2007
@@ -1197,6 +1197,7 @@
     dTHX;
     dPERINTERP;
     SV *flags = sv_2mortal(newSVpv("",0));
+    SV *inner;
     STRLEN lna;
     static const char pad[] = "      ";
     if (!msg)
@@ -1248,17 +1249,28 @@
        PerlIO_printf(DBILOGFP,"%s NUM_OF_FIELDS %d\n", pad, 
DBIc_NUM_FIELDS(imp_sth));
        PerlIO_printf(DBILOGFP,"%s NUM_OF_PARAMS %d\n", pad, 
DBIc_NUM_PARAMS(imp_sth));
     }
+    inner = dbih_inner((SV*)DBIc_MY_H(imp_xxh), msg);
+    if (!inner || !SvROK(inner))
+        return 1;
     if (level > 0) {
         SV* value;
        char *key;
        I32   keylen;
-       SV *inner;
        PerlIO_printf(DBILOGFP,"%s cached attributes:\n", pad);
-       inner = dbih_inner((SV*)DBIc_MY_H(imp_xxh), msg);
        while ( (value = hv_iternextsv((HV*)SvRV(inner), &key, &keylen)) ) {
            PerlIO_printf(DBILOGFP,"%s   '%s' => %s\n", pad, key, 
neatsvpv(value,0));
        }
     }
+    else if (DBIc_TYPE(imp_xxh) == DBIt_DB) {
+        SV **svp = hv_fetch((HV*)SvRV(inner), "Name", 4, 0);
+        if (svp && SvOK(*svp))
+            PerlIO_printf(DBILOGFP,"%s Name %s\n", pad, neatsvpv(*svp,0));
+    }
+    else if (DBIc_TYPE(imp_xxh) == DBIt_ST) {
+        SV **svp = hv_fetch((HV*)SvRV(inner), "Statement", 9, 0);
+        if (svp && SvOK(*svp))
+            PerlIO_printf(DBILOGFP,"%s Statement %s\n", pad, neatsvpv(*svp,0));
+    }
     return 1;
 }
 
@@ -1274,7 +1286,6 @@
     int debug = DBIS_TRACE_LEVEL;
     int auto_dump = (debug >= 6);
     imp_xxh_t * const parent_xxh = DBIc_PARENT_COM(imp_xxh);
-
     /* Note that we're very much on our own here. DBIc_MY_H(imp_xxh) almost    
*/
     /* certainly points to memory which has been freed. Don't use it!          
*/
 
@@ -1382,31 +1393,43 @@
 static AV *
 dbih_setup_fbav(imp_sth_t *imp_sth)
 {
+    /*  Usually called to setup the row buffer for new sth.
+     *  Also called if the value of NUM_OF_FIELDS is altered,
+     *  in which case it adjusts the row buffer to match NUM_OF_FIELDS.
+     */
     dTHX;
     dPERINTERP;
-    int i;
-    AV *av;
+    int i = DBIc_NUM_FIELDS(imp_sth);
+    AV *av = DBIc_FIELDS_AV(imp_sth);
 
-   if (DBIc_FIELDS_AV(imp_sth))
-       return DBIc_FIELDS_AV(imp_sth);
+    if (i < 0)
+        i = 0;
+
+    if (av) {
+        if (av_len(av)+1 == i)  /* is existing array the right size? */
+            return av;
+        /* we need to adjust the size of the array */
+        if (DBIc_TRACE_LEVEL(imp_sth) >= 3)
+            PerlIO_printf(DBILOGFP,"    dbih_setup_fbav realloc from %d to %d 
fields\n", av_len(av)+1, i);
+        SvREADONLY_off(av);
+    }
+    else {
+        if (DBIc_TRACE_LEVEL(imp_sth) >= 3)
+            PerlIO_printf(DBILOGFP,"    dbih_setup_fbav alloc for %d 
fields\n", i);
+        av = newAV();
+        DBIc_FIELDS_AV(imp_sth) = av;
+    }
 
-    i = DBIc_NUM_FIELDS(imp_sth);
-    if (i <= 0 || i > 32000)   /* trap obvious mistakes */
-       croak("dbih_setup_fbav: invalid number of fields: %d%s",
-               i, ", NUM_OF_FIELDS attribute probably not set right");
-    av = newAV();
-    if (DBIS_TRACE_LEVEL >= 3)
-       PerlIO_printf(DBILOGFP,"    dbih_setup_fbav for %d fields => 0x%lx\n",
-                   i, (long)av);
     /* load array with writeable SV's. Do this backwards so    */
     /* the array only gets extended once.                      */
     while(i--)                 /* field 1 stored at index 0    */
        av_store(av, i, newSV(0));
+    if (DBIc_TRACE_LEVEL(imp_sth) >= 3)
+        PerlIO_printf(DBILOGFP,"    dbih_setup_fbav now %d fields\n", 
av_len(av)+1);
     SvREADONLY_on(av);         /* protect against shift @$row etc */
     /* row_count will need to be manually reset by the driver if the   */
     /* sth is re-executed (since this code won't get rerun)            */
     DBIc_ROW_COUNT(imp_sth) = 0;
-    DBIc_FIELDS_AV(imp_sth) = av;
     return av;
 }
 
@@ -1423,12 +1446,14 @@
        dTHX;
        int i = av_len(av) + 1;
         if (i != DBIc_NUM_FIELDS(imp_sth)) {
-            SV *sth = dbih_inner((SV*)DBIc_MY_H(imp_sth), "_get_fbav");
+            /*SV *sth = dbih_inner((SV*)DBIc_MY_H(imp_sth), "_get_fbav");*/
             /* warn via PrintWarn */
             set_err_char(SvRV(DBIc_MY_H(imp_sth)), (imp_xxh_t*)imp_sth,
-                    "0", 0, "Number of row fields inconsistent with 
NUM_OF_FIELDS, NUM_OF_FIELDS updated", "", "_get_fbav");
+                    "0", 0, "Number of row fields inconsistent with 
NUM_OF_FIELDS (driver bug)", "", "_get_fbav");
+            /*
             DBIc_NUM_FIELDS(imp_sth) = i;
             hv_delete((HV*)SvRV(sth), "NUM_OF_FIELDS", 13, G_DISCARD);
+            */
         }
        /* don't let SvUTF8 flag persist from one row to the next   */
        /* (only affects drivers that use sv_setpv, but most XS do) */
@@ -1719,20 +1744,16 @@
     }
     else if (htype==DBIt_ST && strEQ(key, "NUM_OF_FIELDS")) {
        D_imp_sth(h);
+        int new_num_fields = (SvOK(valuesv)) ? SvIV(valuesv) : -1;
+
        if (DBIc_NUM_FIELDS(imp_sth) > 0        /* don't change NUM_FIELDS! */
         &&  DBIc_ACTIVE(imp_sth)                /* if sth is Active */
         ) {
            croak("Can't change NUM_OF_FIELDS of Active handle (already set to 
%d)", DBIc_NUM_FIELDS(imp_sth));
         }
-        if (DBIc_NUM_FIELDS(imp_sth) > 0
-        && SvIV(valuesv) != DBIc_NUM_FIELDS(imp_sth)
-        && DBIc_TRACE_LEVEL(imp_sth)
-        && DBIc_FIELDS_AV(imp_sth)
-        ) {
-            PerlIO_printf(DBILOGFP,"Changing NUM_OF_FIELDS (from %d to %d) 
after row buffer already allocated\n",
-                    DBIc_NUM_FIELDS(imp_sth), (int)SvIV(valuesv));
-        }
-       DBIc_NUM_FIELDS(imp_sth) = (SvOK(valuesv)) ? SvIV(valuesv) : -1;
+       DBIc_NUM_FIELDS(imp_sth) = new_num_fields;
+        if (DBIc_FIELDS_AV(imp_sth)) /* modify existing fbav */
+            dbih_setup_fbav(imp_sth);
        cacheit = 1;
     }
     else if (htype==DBIt_ST && strEQ(key, "NUM_OF_PARAMS")) {

Modified: dbi/trunk/lib/DBD/Gofer.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer.pm  (original)
+++ dbi/trunk/lib/DBD/Gofer.pm  Wed Feb 21 17:44:25 2007
@@ -266,7 +266,6 @@
     # Methods that should be forwarded if policy says so
     for my $method (qw(
         quote
-        quote_identifier
     )) {
         no strict 'refs';
         # XXX add policy checks
@@ -440,6 +439,7 @@
             $sth->more_results;
         }
         else {
+            $sth->STORE(Active => 0);
             $sth->{go_rows} = $response->rv;
         }
         # set error/warn/info (after more_results as that'll clear err)
@@ -483,6 +483,7 @@
 
         my $meta = shift @$resultset_list
             or return undef; # no more result sets
+        #warn "more_results: ".Data::Dumper::Dumper($meta);
 
         # pull out the special non-atributes first
         my ($rowset, $err, $errstr, $state)
@@ -713,11 +714,11 @@
 Some driver-private dbh attributes may not be available if the driver has not
 implemented the private_attribute_info() method (added in DBI 1.54).
 
-=head1 Multiple Resultsets
+=head2 Multiple Resultsets
 
 Multiple resultsets are supported if the driver supports the more_results() 
method.
 
-=head1 Use of last_insert_id requires a minor code change
+=head2 Use of last_insert_id requires a minor code change
 
 To enable use of last_insert_id you need to indicate to DBD::Gofer that you'd
 like to use it.  You do that my adding a C<go_last_insert_id_args> attribute to
@@ -736,6 +737,18 @@
 
 XXX allow $dbh->{go_last_insert_id_args} = [] to enable it by default?
 
+=head2 Statement activity that also updates dbh attributes
+
+Some drivers may update one or more dbh attributes after performing activity on
+a child sth.  For example, DBD::mysql provides $dbh->{mysql_insertid} in 
addition to
+$sth->{mysql_insertid}. Currently this isn't supported, but probably needs to 
be.
+
+=head2 Methods that report an error always return undef
+
+With DBD::Gofer a method that sets an error always return an undef or empty 
list.
+That shouldn't be a problem in practice because the DBI doesn't define any
+methods that do return meaningful values while also reporting an error.
+
 =head1 TRANSPORTS
 
 DBD::Gofer doesn't concern itself with transporting requests and responses to 
and fro.

Modified: dbi/trunk/lib/DBD/Gofer/Policy/rush.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Policy/rush.pm      (original)
+++ dbi/trunk/lib/DBD/Gofer/Policy/rush.pm      Wed Feb 21 17:44:25 2007
@@ -17,8 +17,8 @@
 __PACKAGE__->create_default_policy_subs({
 
     # Skipping the connect check is fast, but it also skips
-    # setting dbh attributes! Make sure that your application doesn't
-    # need changing dbh attributes between requests
+    # fetching the remote dbh attributes!
+    # Make sure that your application doesn't need access to dbh attributes.
     skip_connect_check => 1,
 
     # most code doesn't rely on sth attributes being set after prepare

Modified: dbi/trunk/lib/DBI/DBD.pm
==============================================================================
--- dbi/trunk/lib/DBI/DBD.pm    (original)
+++ dbi/trunk/lib/DBI/DBD.pm    Wed Feb 21 17:44:25 2007
@@ -1237,6 +1237,53 @@
 to the B<DBI>'s own method which does the right thing based
 on the number of calls to C<_set_fbav()>.
 
+=head4 The more_results method
+
+If your driver doesn't support multiple result sets, then don't even implement 
this method.
+
+Otherwise, this method needs to get the statement handle ready to fetch results
+from the next result set, if there is one. Typically you'd start with:
+
+    $sth->finish;
+
+then you should delete all the attributes from the attribute cache that may no
+longer be relevant for the new result set:
+
+    delete $sth->{$_}
+        for qw(NAME TYPE PRECISION SCALE ...);
+
+for drivers written in C use:
+
+    hv_delete((HV*)SvRV(sth), "NAME", 4, G_DISCARD);
+    hv_delete((HV*)SvRV(sth), "NULLABLE", 8, G_DISCARD);
+    hv_delete((HV*)SvRV(sth), "NUM_OF_FIELDS", 13, G_DISCARD);
+    hv_delete((HV*)SvRV(sth), "PRECISION", 9, G_DISCARD);
+    hv_delete((HV*)SvRV(sth), "SCALE", 5, G_DISCARD);
+    hv_delete((HV*)SvRV(sth), "TYPE", 4, G_DISCARD);
+
+Don't forget to also delete, or update, any driver-private attributes that may
+not be correct for the next resultset.
+
+The NUM_OF_FIELDS attribute is a special case. It should be set using STORE:
+
+    $sth->STORE(NUM_OF_FIELDS => 0); /* for DBI <= 1.53 */
+    $sth->STORE(NUM_OF_FIELDS => $new_value);
+
+for drivers written in C use this incantation:
+
+    /* Adjust NUM_OF_FIELDS - which also adjusts the row buffer size */
+    DBIc_NUM_FIELDS(imp_sth) = 0; /* for DBI <= 1.53 */
+    DBIS->set_attr_k(sth, sv_2mortal(newSVpvn("NUM_OF_FIELDS",13)), 0,
+        sv_2mortal(newSViv(mysql_num_fields(imp_sth->result)))
+    );
+
+For DBI versions prior to 1.54 you'll also need to explicitly adjust the
+number of elements in the row buffer array (C<DBIc_FIELDS_AV(imp_sth)>)
+to match the new result set. Fill any new values with newSV(0) not &sv_undef.
+Alternatively you could free DBIc_FIELDS_AV(imp_sth) and set it to null,
+but that would mean bind_columns() woudn't work across result sets.
+
+
 =head4 Statement attributes
 
 The main difference between I<dbh> and I<sth> attributes is, that you
@@ -1245,7 +1292,7 @@
 L<DBI/Statement Handle Attributes> for a complete list.
 
 Pay attention to attributes which are marked as read only, such as
-I<NUM_OF_FIELDS>. These attributes can only be set the first time
+I<NUM_OF_PARAMS>. These attributes can only be set the first time
 a statement is executed. If a statement is prepared, then executed
 multiple times, warnings may be generated.
 
@@ -1253,9 +1300,9 @@
 of attributes which might be expensive to calculate (such as the
 I<NAME> and I<NAME_*> attributes):
 
-    my $storedNumFields = $sth->FETCH('NUM_OF_FIELDS');
-    if (!defined $storedNumFields or $storedNumFields < 0) {
-        $sth->STORE('NUM_OF_FIELDS') = $numFields;
+    my $storedNumParams = $sth->FETCH('NUM_OF_PARAMS');
+    if (!defined $storedNumParams or $storedNumFields < 0) {
+        $sth->STORE('NUM_OF_PARAMS') = $numParams;
 
         # Set other useful attributes that only need to be set once
         # for a statement, like $sth->{NAME} and $sth->{TYPE}
@@ -2117,9 +2164,9 @@
 
   DBIc_NUM_PARAMS(imp_sth) = ...
 
-If you can, you should also setup attributes like I<NUM_OF_FIELDS>,
-I<NAME>, ... here, but B<DBI> doesn't require that. However, if you do,
-document it.
+If you can, you should also setup attributes like I<NUM_OF_FIELDS>, I<NAME>,
+etc. here, but B<DBI> doesn't require that - they can be deferred until
+execute() is called. However, if you do, document it.
 
 In any case you should set the I<IMPSET> flag, as you did in
 C<dbd_db_connect()> above:
@@ -2175,8 +2222,8 @@
   }
 
 It is important that the I<ACTIVE> flag only be set for C<SELECT>
-statements (or any other statements that can return multiple sets
-of values from the database using a cursor-like mechanism). See
+statements (or any other statements that can return many
+values from the database using a cursor-like mechanism). See
 C<dbd_db_connect()> above for more explanations.
 
 There plans for a preparse function to be provided by B<DBI>, but this has

Modified: dbi/trunk/lib/DBI/Gofer/Execute.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Execute.pm  (original)
+++ dbi/trunk/lib/DBI/Gofer/Execute.pm  Wed Feb 21 17:44:25 2007
@@ -56,10 +56,18 @@
     # which would reduce processing/traffic for non-select statements
     mysql  => {
         dbh => [qw(
+            mysql_errno mysql_error mysql_hostinfo mysql_info mysql_insertid
+            mysql_protoinfo mysql_serverinfo mysql_stat mysql_thread_id
         )],
         sth => [qw(
             mysql_is_blob mysql_is_key mysql_is_num mysql_is_pri_key 
mysql_is_auto_increment
-            mysql_length mysql_max_length mysql_table mysql_type 
mysql_type_name
+            mysql_length mysql_max_length mysql_table mysql_type 
mysql_type_name mysql_insertid
+        )],
+        # XXX this dbh_after_sth stuff is a temporary, but important, hack.
+        # should be done via hash instead of arrays where the hash value 
contains
+        # flags that can indicate which attributes need to be handled in this 
way
+        dbh_after_sth => [qw(
+            mysql_insertid
         )],
     },
     Pg  => {
@@ -311,15 +319,24 @@
     };
     my $response = $self->new_response_with_err($rv, $@);
 
-    $response->last_insert_id( $last_insert_id ) if defined $last_insert_id;
+    $response->last_insert_id( $last_insert_id )
+        if defined $last_insert_id;
 
+    # XXX would be nice to be able to support streaming of results
     # even if the eval failed we still want to try to gather attribute values
-    $response->sth_resultsets( $self->gather_sth_resultsets($sth, $request) ) 
if $sth;
+    $response->sth_resultsets( $self->gather_sth_resultsets($sth, $request) )
+        if $sth;
+
+    if (my $dbh_attr = $extra_attr{$dbh->{Driver}{Name}}{dbh_after_sth}) {
+        my %dbh_attr_values;
+        $dbh_attr_values{$_} = $dbh->FETCH($_) for @$dbh_attr;
+        $response->dbh_attributes(\%dbh_attr_values);
+    }
 
-    # XXX would be nice to be able to support streaming of results
     # which would reduce memory usage and latency for large results
 
-    $self->reset_dbh($dbh) if $dbh;
+    $self->reset_dbh($dbh)
+        if $dbh;
 
     return $response;
 }

Modified: dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       (original)
+++ dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       Wed Feb 21 17:44:25 2007
@@ -43,7 +43,7 @@
     my $frozen_response = $transport->freeze_data($response);
     print $frozen_response;
 
-    return MP2 ? Apache2::Const::OK : Apache::Constants::OK;
+    return OK;
 }
 
 

Modified: dbi/trunk/t/12quote.t
==============================================================================
--- dbi/trunk/t/12quote.t       (original)
+++ dbi/trunk/t/12quote.t       Wed Feb 21 17:44:25 2007
@@ -45,3 +45,5 @@
 }
 
 check_quote_identifier();
+
+1;

Reply via email to