ID: 16960
Updated by: [EMAIL PROTECTED]
Reported By: [EMAIL PROTECTED]
Status: Open
Bug Type: Feature/Change Request
Operating System: All
PHP Version: 4.0CVS-2002-05-02
New Comment:
OK, more to come. The following patch solves the issues of corrupt
objects, a missing function sybase_fetch_assoc() function and the loss
of fields with similar names while including my previous patch.
* Corrupt objects
sybase_fetch_object() returns object with numeric member
variables, which cannot be accessed, e.g.
object() {
0 => 'bar',
'foo' => 'bar'
}
$obj->0 will fail.
* Identical fieldnames
Joining over 2 or more tables and selecting fields with
the same fieldname, you will lose information using the
string keys:
select a.lastchange, b.lastchange [...]
array() {
0 => 'May 02 2002 05:49PM',
'lastchange' => 'May 02 2002 05:49PM',
1 => 'Apr 03 2002 12:22PM'
}
Patch returns this using sybase_fetch_assoc():
array() {
'lastchange' => 'May 02 2002 05:49PM',
'lastchange1'=> 'Apr 03 2002 12:22PM'
)
No BC issues on this, AFAIS.
[patch-ext_sybase_ct_php_sybase_ct.c]
--- php4-200205012100/ext/sybase_ct/php_sybase_ct.c Tue Mar 12 21:34:06
2002
+++ __build__/ext/sybase_ct/php_sybase_ct.c Thu May 2 17:39:46 2002
@@ -48,6 +48,7 @@
PHP_FE(sybase_num_fields, NULL)
PHP_FE(sybase_fetch_row, NULL)
PHP_FE(sybase_fetch_array, NULL)
+ PHP_FE(sybase_fetch_assoc, NULL)
PHP_FE(sybase_fetch_object, NULL)
PHP_FE(sybase_data_seek, NULL)
PHP_FE(sybase_fetch_field, NULL)
@@ -57,22 +58,23 @@
PHP_FE(sybase_min_client_severity, NULL)
PHP_FE(sybase_min_server_severity, NULL)
- PHP_FALIAS(mssql_connect, sybase_connect,
NULL)
- PHP_FALIAS(mssql_pconnect, sybase_pconnect,
NULL)
- PHP_FALIAS(mssql_close, sybase_close,
NULL)
- PHP_FALIAS(mssql_select_db, sybase_select_db,
NULL)
- PHP_FALIAS(mssql_query, sybase_query,
NULL)
+ PHP_FALIAS(mssql_connect, sybase_connect, NULL)
+ PHP_FALIAS(mssql_pconnect, sybase_pconnect, NULL)
+ PHP_FALIAS(mssql_close, sybase_close, NULL)
+ PHP_FALIAS(mssql_select_db, sybase_select_db, NULL)
+ PHP_FALIAS(mssql_query, sybase_query, NULL)
PHP_FALIAS(mssql_free_result, sybase_free_result, NULL)
PHP_FALIAS(mssql_get_last_message, sybase_get_last_message,NULL)
- PHP_FALIAS(mssql_num_rows, sybase_num_rows,
NULL)
+ PHP_FALIAS(mssql_num_rows, sybase_num_rows, NULL)
PHP_FALIAS(mssql_num_fields, sybase_num_fields, NULL)
- PHP_FALIAS(mssql_fetch_row, sybase_fetch_row,
NULL)
+ PHP_FALIAS(mssql_fetch_row, sybase_fetch_row, NULL)
PHP_FALIAS(mssql_fetch_array, sybase_fetch_array, NULL)
+ PHP_FALIAS(mssql_fetch_assoc, sybase_fetch_assoc, NULL)
PHP_FALIAS(mssql_fetch_object, sybase_fetch_object, NULL)
- PHP_FALIAS(mssql_data_seek, sybase_data_seek,
NULL)
+ PHP_FALIAS(mssql_data_seek, sybase_data_seek, NULL)
PHP_FALIAS(mssql_fetch_field, sybase_fetch_field, NULL)
PHP_FALIAS(mssql_field_seek, sybase_field_seek, NULL)
- PHP_FALIAS(mssql_result, sybase_result,
NULL)
+ PHP_FALIAS(mssql_result, sybase_result, NULL)
PHP_FALIAS(mssql_affected_rows, sybase_affected_rows, NULL)
PHP_FALIAS(mssql_min_client_severity, sybase_min_client_severity, NULL)
PHP_FALIAS(mssql_min_server_severity, sybase_min_server_severity, NULL)
@@ -230,7 +232,8 @@
TSRMLS_FETCH();
if (srvmsg->severity >= SybCtG(min_server_severity)) {
- php_error(E_WARNING, "Sybase: Server message: %s (severity %d,
procedure %s)",
+ php_error(E_WARNING, "Sybase: Server message #%d: %s (severity %d,
procedure %s)",
+ srvmsg->msgnumber,
srvmsg->text, srvmsg->severity,
((srvmsg->proclen>0) ?
srvmsg->proc : "N/A"));
}
STR_FREE(SybCtG(server_message));
@@ -953,33 +956,33 @@
break;
case CS_SMALLINT_TYPE:
datafmt[i].maxlength = 7;
- numerics[i] = 1;
+ numerics[i] = 1;
break;
case CS_INT_TYPE:
datafmt[i].maxlength = 12;
- numerics[i] = 1;
+ numerics[i] = 1;
break;
case CS_REAL_TYPE:
case CS_FLOAT_TYPE:
datafmt[i].maxlength = 24;
- numerics[i] = 1;
- break;
+ numerics[i] = 2;
+ break;
case CS_MONEY_TYPE:
case CS_MONEY4_TYPE:
datafmt[i].maxlength = 24;
- numerics[i] = 0;
+ numerics[i] = 0;
break;
case CS_DATETIME_TYPE:
case CS_DATETIME4_TYPE:
datafmt[i].maxlength = 30;
numerics[i] = 0;
- break;
+ break;
case CS_NUMERIC_TYPE:
case CS_DECIMAL_TYPE:
datafmt[i].maxlength = datafmt[i].precision + 3;
- numerics[i] = 1;
+ numerics[i] = 2;
break;
- default:
+ default:
datafmt[i].maxlength++;
numerics[i] = 0;
break;
@@ -1004,11 +1007,20 @@
result->data[i] = (pval *) emalloc(sizeof(pval)*num_fields);
for (j=0; j<num_fields; j++) {
if (indicators[j] == -1) { /* null value */
- ZVAL_FALSE(&result->data[i][j]);
+ ZVAL_NULL(&result->data[i][j]);
} else {
Z_STRLEN(result->data[i][j]) = lengths[j]-1; /* we
don't need the
NULL in the length */
Z_STRVAL(result->data[i][j]) = estrndup(tmp_buffer[j],
lengths[j]);
Z_TYPE(result->data[i][j]) = IS_STRING;
+
+ /* Here we go, i want those types!:-)
+ * Perhaps there is a nicer way of doing this, instead
+of making
strings first
+ * and then converting them back, but I'm a
+Zend-API-lamer.
+ */
+ switch (numerics[j]) {
+ case 1:
convert_to_long(&result->data[i][j]); break;
+ case 2:
convert_to_double(&result->data[i][j]); numerics[j]= 1; break;
+ }
}
}
}
@@ -1021,7 +1033,7 @@
j=0;
for (i=0; i<num_fields; i++) {
char computed_buf[16];
-
+
if (datafmt[i].namelen>0) {
result->fields[i].name = estrndup(datafmt[i].name,
datafmt[i].namelen);
} else {
@@ -1404,15 +1416,65 @@
result->cur_row++;
}
+static void php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *sybase_result_index;
+ sybase_result *result;
+ int i, j;
+ pval *tmp;
+ char name[32];
+
+ if (ZEND_NUM_ARGS()!=1 || getParameters(ht, 1,
&sybase_result_index)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index,
-1, "Sybase result", le_result);
+
+ if (result->cur_row >= result->num_rows) {
+ RETURN_FALSE;
+ }
+
+ if (array_init(return_value)==FAILURE) {
+ RETURN_FALSE;
+ }
+
+ j= 1;
+ for (i=0; i<result->num_fields; i++) {
+ ALLOC_ZVAL(tmp);
+ *tmp = result->data[result->cur_row][i];
+ INIT_PZVAL(tmp);
+ if (PG(magic_quotes_runtime) && Z_TYPE_P(tmp) == IS_STRING) {
+ Z_STRVAL_P(tmp) = php_addslashes(Z_STRVAL_P(tmp),
+Z_STRLEN_P(tmp),
&Z_STRLEN_P(tmp), 0 TSRMLS_CC);
+ } else {
+ pval_copy_constructor(tmp);
+ }
+ if (zend_hash_exists(Z_ARRVAL_P(return_value),
result->fields[i].name, strlen(result->fields[i].name)+1)) {
+ snprintf(name, 32, "%s%d",
result->fields[i].name, j);
+ j++;
+ zend_hash_update(Z_ARRVAL_P(return_value), name,
+strlen(name)+1,
(void *) &tmp, sizeof(pval *), NULL);
+ } else {
+ zend_hash_update(Z_ARRVAL_P(return_value),
result->fields[i].name, strlen(result->fields[i].name)+1, (void *)
&tmp, sizeof(pval *), NULL);
+ }
+ }
+ result->cur_row++;
+}
/* {{{ proto object sybase_fetch_object(int result)
Fetch row as object */
PHP_FUNCTION(sybase_fetch_object)
{
- php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (Z_TYPE_P(return_value)==IS_ARRAY) {
object_and_properties_init(return_value,
ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
}
+}
+/* }}} */
+
+/* {{{ proto array sybase_fetch_assoc(int result)
+ Fetch row as array */
+PHP_FUNCTION(sybase_fetch_assoc)
+{
+ php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
Previous Comments:
------------------------------------------------------------------------
[2002-05-02 05:37:17] [EMAIL PROTECTED]
First of all: I'm putting this in here since my mail to
[EMAIL PROTECTED] was rejected thanks to an overefficient spam
protection filter (kundenserver.de).
Please see http://relaytest.kundenserver.de/ for details.
Here's my mail:
--------------------------------------------------------
Hello,
as you might know, the sybase extension is very bad when it comes to
data types, since it returns almost everything as a string, except for
NULL values, which become FALSE.
Short example:
--- SQL -------------------------------
select
NULL as "null",
"string" as string,
6100 as integer,
6.1 as float,
getdate() as date
--- var_dump() of resultset -----------
array(10) {
[0]=>
string(0) ""
["null"]=>
string(0) ""
[1]=>
string(6) "string"
["string"]=>
string(6) "string"
[2]=>
string(4) "6100"
["integer"]=>
string(4) "6100"
[3]=>
string(3) "6.1"
["float"]=>
string(3) "6.1"
[4]=>
string(4) " :"
["date"]=>
string(4) " :"
}
Well, when writing applications communicating via SOAP with
type-secure
languages - in my case PHP as server, Java as client - this comes
quite
unhandy, since on ends up going through the resultset and changing
types
for each entry, thus producing unnecessary overhead.
Something like this would be much nicer:
--- var_dump() of resultset -----------
array(10) {
[0]=>
NULL
["null"]=>
NULL
[1]=>
string(6) "string"
["string"]=>
string(6) "string"
[2]=>
int(6100)
["integer"]=>
int(6100)
[3]=>
float(6.1)
["float"]=>
float(6.1)
[4]=>
string(19) "May 02 2002 11:15AM"
["date"]=>
string(19) "May 02 2002 11:15AM"
}
OK, so I went ahead and patched ext/sybase_ct/php_sybase_ct.c to
accomplish my wishes. I must admit though I'm a total lamer when it
goes
to writing C sourcecode and utilizing the Zend API, so - after
studying
a couple of files, wrote a couple of lines, compiled, watched the
thing
segfault once or twice, I finally managed to get a running PHP binary
and a sybase_ct.so compiled.
Attached is the patch, however ugly it may be, it compiles and
produces
the resultset as intended - maybe you guys want to take a look at it
and correct it to be much nicer and much better:-)
--
Timm Friebe
Systems developer Schlund+Partner AG
Karlsruhe, Germany
[patch-ext_sybase_ct_php_sybase_ct.c]
--- php4-200205012100/ext/sybase_ct/php_sybase_ct.c Tue Mar 12 21:34:06
2002
+++ __build__/ext/sybase_ct/php_sybase_ct.c Thu May 2 10:47:53 2002
@@ -953,33 +953,33 @@
break;
case CS_SMALLINT_TYPE:
datafmt[i].maxlength = 7;
- numerics[i] = 1;
+ numerics[i] = 1;
break;
case CS_INT_TYPE:
datafmt[i].maxlength = 12;
- numerics[i] = 1;
+ numerics[i] = 1;
break;
case CS_REAL_TYPE:
case CS_FLOAT_TYPE:
datafmt[i].maxlength = 24;
- numerics[i] = 1;
- break;
+ numerics[i] = 2;
+ break;
case CS_MONEY_TYPE:
case CS_MONEY4_TYPE:
datafmt[i].maxlength = 24;
- numerics[i] = 0;
+ numerics[i] = 0;
break;
case CS_DATETIME_TYPE:
case CS_DATETIME4_TYPE:
datafmt[i].maxlength = 30;
numerics[i] = 0;
- break;
+ break;
case CS_NUMERIC_TYPE:
case CS_DECIMAL_TYPE:
datafmt[i].maxlength = datafmt[i].precision + 3;
- numerics[i] = 1;
+ numerics[i] = 2;
break;
- default:
+ default:
datafmt[i].maxlength++;
numerics[i] = 0;
break;
@@ -1004,11 +1004,19 @@
result->data[i] = (pval *) emalloc(sizeof(pval)*num_fields);
for (j=0; j<num_fields; j++) {
if (indicators[j] == -1) { /* null value */
- ZVAL_FALSE(&result->data[i][j]);
+ ZVAL_NULL(&result->data[i][j]);
} else {
Z_STRLEN(result->data[i][j]) = lengths[j]-1; /* we
don't need the
NULL in the length */
Z_STRVAL(result->data[i][j]) = estrndup(tmp_buffer[j],
lengths[j]);
Z_TYPE(result->data[i][j]) = IS_STRING;
+
+ // Here we go, i want those types!:-)
+ // Perhaps there is a nicer way of doing this, instead
+of making
strings first
+ // and then converting them back, but I'm a
+Zend-API-lamer.
+ switch (numerics[j]) {
+ case 1:
convert_to_long(&result->data[i][j]); break;
+ case 2:
convert_to_double(&result->data[i][j]); numerics[j]= 1; break;
+ }
}
}
}
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=16960&edit=1