Hi!
I wrote:
> What I disliked (like the PEAR people) is the missing of a
> row counter when fetching rows from Postgres result tables.
>
> The mysql/ODBC/Adabas/some-other - way is:
>
> $dbr = xxx_exec ($connection, $query);
> while (list ($a, $b, $c) = xxx_fetch_row ($dbr)) {
> ... // Great, I have my results
> }
>
> The traditional and only Postgres way is:
>
> $dbr = xxx_exec ($connection, $query);
> $cnt = pg_num_rows ($dbr);
> for ($i = 0; $i < $cnt; $i++) {
> list ($a, $b, $c) = pg_fetch_row ($dbr, $i)
> }
Now, the patch for PHP 4.0.5 is attached, together with
a description.
Could anybody with CVS access test it / apply it?
I think who writes the code should also do some documentation.
I do not know the "source format" of the documentation and
where to get it - could somebody mail me the Postgres-Doc-
Sources?
Thanks a lot,
Georg
------------ snip ------------- description ----------
The patch enables the Postgresql-driver to do the
row counting within the driver when iterating through
an array. It does this by adding a row counter to
the internal data structure of the postgres result
set.
Instead of writing:
$dbr = pg_exec ($connection, $query);
$cnt = pg_numrows ($dbr);
for ($i = 0; $i < $cnt; $i++) {
list ($a, $b, $c) = pg_fetch_row ($dbr, $i)
... // Got the data here
}
one *can* write:
$dbr = pg_exec ($connection, $query);
while (list ($a, $b, $c) = pg_fetch_row ($dbr)) {
... // Great, I have my results
}
This unifies the behaviour with other PHP database drivers
and helps the PEAR-libary developers (see notes there).
Moreover, one can e.g. write:
$dbr = pg_exec ("SELECT MAX(id)+1 FROM table");
// Try to get the new id
if (! ($newid = pg_result ($dbr, 0)))
$newid = 1; // No row found
// Insert with the new id here
instead of verifying first if a row is available.
This is a description of the API change:
The following functions have a different syntax
PG_RESULT
Old syntax: pg_result (<resultset>, <row>, <field>)
New syntax: pg_result (<resultset>, [<row>,] <field>)
Change:
If row is ommited, the result is taken from the current data
row. If no row has been fetched yet, the first row will be
fetched. If there is no result row, false will be silently
returned without an error message.
Traditional behaviour is not affected.
PG_FETCH_ROW / PG_FETCH_ARRAY / PG_FETCH_OBJECT
Old syntax: pg_fetch_<func> (<resultset>, <row> [, <resulttype>])
New syntax: pg_fetch_<func> (<resultset>, [<row> [, <resulttype>]])
Change:
If row is ommited, the next row is fetched.
If row is ommited, and the last row is reached, no error will
be written, but silently false returned. Traditional behaviour
not affected.
It is not possible to ommit the row but to specify a resulttype.
PG_FIELDPRTLEN / PG_FIELDISNULL
Old syntax: pg_field<func> (<resultset>, <row>, <field>)
New syntax: pg_field<func> (<resultset>, [<row>,] <field>)
Change:
If row is ommited, the result is taken from the current data
row. If no row has been fetched yet, the first row will be
fetched. If there is no result row, false will be silently
returned without an error message.
Traditional behaviour is not affected.
------------ snip ------------- patch ----------
diff -r -c php-4.0.5.orig/ext/pgsql/pgsql.c php-4.0.5/ext/pgsql/pgsql.c
*** php-4.0.5.orig/ext/pgsql/pgsql.c Wed Apr 4 23:51:58 2001
--- php-4.0.5/ext/pgsql/pgsql.c Wed Jun 20 13:20:38 2001
***************
*** 713,718 ****
--- 713,719 ----
pg_result = (pgsql_result_handle *)
emalloc(sizeof(pgsql_result_handle));
pg_result->conn = pgsql;
pg_result->result = pgsql_result;
+ pg_result->row = -1;
ZEND_REGISTER_RESOURCE(return_value, pg_result,
le_result);
/*
return_value->value.lval =
zend_list_insert(pg_result,le_result);
***************
*** 1010,1029 ****
zval **result, **row, **field=NULL;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int field_offset;
! if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row,
&field)==FAILURE) {
WRONG_PARAM_COUNT;
}
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
!
! convert_to_long_ex(row);
! if (Z_LVAL_PP(row) < 0 || Z_LVAL_PP(row) >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL result
index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
}
switch(Z_TYPE_PP(field)) {
case IS_STRING:
--- 1011,1040 ----
zval **result, **row, **field=NULL;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int field_offset, pgsql_row;
! if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row,
&field)==FAILURE) &&
! (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result,
&field)==FAILURE)) {
WRONG_PARAM_COUNT;
}
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
! if (ZEND_NUM_ARGS() == 2) {
! if (pg_result->row < 0)
! pg_result->row = 0;
! pgsql_row = pg_result->row;
! if (pgsql_row >= PQntuples(pgsql_result)) {
! RETURN_FALSE;
! }
! } else {
! convert_to_long_ex(row);
! pgsql_row = Z_LVAL_PP(row);
! if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL
result index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
! }
}
switch(Z_TYPE_PP(field)) {
case IS_STRING:
***************
*** 1039,1048 ****
RETURN_FALSE;
}
! if (PQgetisnull(pgsql_result, Z_LVAL_PP(row), field_offset)) {
return_value->type = IS_NULL;
} else {
! return_value->value.str.val = PQgetvalue(pgsql_result, Z_LVAL_PP(row),
field_offset);
return_value->value.str.len = (return_value->value.str.val ?
strlen(return_value->value.str.val) : 0);
return_value->value.str.val =
safe_estrndup(return_value->value.str.val,return_value->value.str.len);
return_value->type = IS_STRING;
--- 1050,1059 ----
RETURN_FALSE;
}
! if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
return_value->type = IS_NULL;
} else {
! return_value->value.str.val = PQgetvalue(pgsql_result, pgsql_row,
field_offset);
return_value->value.str.len = (return_value->value.str.val ?
strlen(return_value->value.str.val) : 0);
return_value->value.str.val =
safe_estrndup(return_value->value.str.val,return_value->value.str.len);
return_value->type = IS_STRING;
***************
*** 1056,1067 ****
zval **result, **row, **arg3;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int i, num_fields;
char *element, *field_name;
uint element_len;
PLS_FETCH();
switch (ZEND_NUM_ARGS()) {
case 2:
if (zend_get_parameters_ex(2, &result, &row)==FAILURE) {
RETURN_FALSE;
--- 1067,1086 ----
zval **result, **row, **arg3;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int i, num_fields, pgsql_row;
char *element, *field_name;
uint element_len;
PLS_FETCH();
switch (ZEND_NUM_ARGS()) {
+ case 1:
+ if (zend_get_parameters_ex(1, &result)==FAILURE) {
+ RETURN_FALSE;
+ }
+ if (!result_type) {
+ result_type = PGSQL_BOTH;
+ }
+ break;
case 2:
if (zend_get_parameters_ex(2, &result, &row)==FAILURE) {
RETURN_FALSE;
***************
*** 1085,1099 ****
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
!
! convert_to_long_ex(row);
! if (Z_LVAL_PP(row) < 0 || Z_LVAL_PP(row) >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL result
index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
}
array_init(return_value);
for (i = 0, num_fields = PQnfields(pgsql_result); i<num_fields; i++) {
! if (PQgetisnull(pgsql_result, Z_LVAL_PP(row), i)) {
if (result_type & PGSQL_NUM) {
add_index_null(return_value, i);
}
--- 1104,1128 ----
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
!
! if (ZEND_NUM_ARGS() == 1) {
! pg_result->row++;
! pgsql_row = pg_result->row;
! if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
! RETURN_FALSE;
! }
! } else {
! convert_to_long_ex(row);
! pgsql_row = Z_LVAL_PP(row);
! pg_result->row = pgsql_row;
! if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL
result index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
! }
}
array_init(return_value);
for (i = 0, num_fields = PQnfields(pgsql_result); i<num_fields; i++) {
! if (PQgetisnull(pgsql_result, pgsql_row, i)) {
if (result_type & PGSQL_NUM) {
add_index_null(return_value, i);
}
***************
*** 1102,1108 ****
add_assoc_null(return_value, field_name);
}
} else {
! element = PQgetvalue(pgsql_result, Z_LVAL_PP(row), i);
element_len = (element ? strlen(element) : 0);
if (element) {
char *data;
--- 1131,1137 ----
add_assoc_null(return_value, field_name);
}
} else {
! element = PQgetvalue(pgsql_result, pgsql_row, i);
element_len = (element ? strlen(element) : 0);
if (element) {
char *data;
***************
*** 1169,1189 ****
zval **result, **row, **field;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int field_offset;
! if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row,
&field)==FAILURE) {
WRONG_PARAM_COUNT;
}
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
!
! convert_to_long_ex(row);
! if (Z_LVAL_PP(row) < 0 || Z_LVAL_PP(row) >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL result
index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
}
switch(Z_TYPE_PP(field)) {
case IS_STRING:
convert_to_string_ex(field);
--- 1198,1229 ----
zval **result, **row, **field;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
! int field_offset, pgsql_row;
! if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &result, &row,
&field)==FAILURE) &&
! (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &result,
&field)==FAILURE)) {
WRONG_PARAM_COUNT;
}
ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, result, -1, "PostgreSQL
result", le_result);
pgsql_result = pg_result->result;
! if (ZEND_NUM_ARGS() == 2) {
! if (pg_result->row < 0)
! pg_result->row = 0;
! pgsql_row = pg_result->row;
! if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
! RETURN_FALSE;
! }
! } else {
! convert_to_long_ex(row);
! pgsql_row = Z_LVAL_PP(row);
! if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
! php_error(E_WARNING,"Unable to jump to row %d on PostgreSQL
result index %d", Z_LVAL_PP(row), Z_LVAL_PP(result));
! RETURN_FALSE;
! }
}
+
switch(Z_TYPE_PP(field)) {
case IS_STRING:
convert_to_string_ex(field);
***************
*** 1201,1210 ****
switch (entry_type) {
case PHP_PG_DATA_LENGTH:
! return_value->value.lval = PQgetlength(pgsql_result,
Z_LVAL_PP(row), field_offset);
break;
case PHP_PG_DATA_ISNULL:
! return_value->value.lval = PQgetisnull(pgsql_result,
Z_LVAL_PP(row), field_offset);
break;
}
return_value->type = IS_LONG;
--- 1241,1250 ----
switch (entry_type) {
case PHP_PG_DATA_LENGTH:
! return_value->value.lval = PQgetlength(pgsql_result,
pgsql_row, field_offset);
break;
case PHP_PG_DATA_ISNULL:
! return_value->value.lval = PQgetisnull(pgsql_result,
pgsql_row, field_offset);
break;
}
return_value->type = IS_LONG;
diff -r -c php-4.0.5.orig/ext/pgsql/php_pgsql.h php-4.0.5/ext/pgsql/php_pgsql.h
*** php-4.0.5.orig/ext/pgsql/php_pgsql.h Wed Apr 4 23:51:58 2001
--- php-4.0.5/ext/pgsql/php_pgsql.h Wed Jun 20 13:29:50 2001
***************
*** 111,116 ****
--- 111,117 ----
typedef struct _php_pgsql_result_handle {
PGconn *conn;
PGresult *result;
+ int row;
} pgsql_result_handle;
typedef struct {
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]