Skip to content

Commit 7a89157

Browse files
committed
PDO MySQL: Fix nextRowset() on libmysqlclient with native PS
The logic after next_result should match the one after execute. This was the case for mysqlnd but not libmysqlclient, which used the non-PS logic.
1 parent 81f012a commit 7a89157

File tree

2 files changed

+79
-93
lines changed

2 files changed

+79
-93
lines changed

ext/pdo_mysql/mysql_statement.c

Lines changed: 79 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ static int pdo_mysql_fill_stmt_from_result(pdo_stmt_t *stmt) /* {{{ */
158158
}
159159
/* }}} */
160160

161-
#ifdef PDO_USE_MYSQLND
162161
static bool pdo_mysql_stmt_after_execute_prepared(pdo_stmt_t *stmt) {
163162
pdo_mysql_stmt *S = stmt->driver_data;
164163
pdo_mysql_db_handle *H = S->H;
165164

165+
#ifdef PDO_USE_MYSQLND
166166
/* For SHOW/DESCRIBE and others the column/field count is not available before execute. */
167167
php_pdo_stmt_set_column_count(stmt, mysql_stmt_field_count(S->stmt));
168168
for (int i = 0; i < stmt->column_count; i++) {
@@ -180,17 +180,90 @@ static bool pdo_mysql_stmt_after_execute_prepared(pdo_stmt_t *stmt) {
180180
}
181181
}
182182
}
183+
#else
184+
/* figure out the result set format, if any */
185+
S->result = mysql_stmt_result_metadata(S->stmt);
186+
if (S->result) {
187+
int calc_max_length = H->buffered && S->max_length == 1;
188+
S->fields = mysql_fetch_fields(S->result);
189+
190+
php_pdo_stmt_set_column_count(stmt, (int)mysql_num_fields(S->result));
191+
S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
192+
S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
193+
S->out_length = ecalloc(stmt->column_count, sizeof(zend_ulong));
194+
195+
/* summon memory to hold the row */
196+
for (int i = 0; i < stmt->column_count; i++) {
197+
if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
198+
my_bool on = 1;
199+
mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
200+
calc_max_length = 0;
201+
}
202+
switch (S->fields[i].type) {
203+
case FIELD_TYPE_INT24:
204+
S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
205+
break;
206+
case FIELD_TYPE_LONG:
207+
S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
208+
break;
209+
case FIELD_TYPE_LONGLONG:
210+
S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
211+
break;
212+
case FIELD_TYPE_TINY:
213+
S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
214+
break;
215+
case FIELD_TYPE_SHORT:
216+
S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
217+
break;
218+
default:
219+
S->bound_result[i].buffer_length =
220+
S->fields[i].max_length? S->fields[i].max_length:
221+
S->fields[i].length;
222+
/* work-around for longtext and alike */
223+
if (S->bound_result[i].buffer_length > H->max_buffer_size) {
224+
S->bound_result[i].buffer_length = H->max_buffer_size;
225+
}
226+
}
227+
228+
/* there are cases where the length reported by mysql is too short.
229+
* eg: when describing a table that contains an enum column. Since
230+
* we have no way of knowing the true length either, we'll bump up
231+
* our buffer size to a reasonable size, just in case */
232+
if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
233+
S->bound_result[i].buffer_length = 128;
234+
}
235+
236+
S->out_length[i] = 0;
237+
238+
S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
239+
S->bound_result[i].is_null = &S->out_null[i];
240+
S->bound_result[i].length = &S->out_length[i];
241+
S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
242+
}
243+
244+
if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
245+
pdo_mysql_error_stmt(stmt);
246+
PDO_DBG_RETURN(0);
247+
}
248+
249+
/* if buffered, pre-fetch all the data */
250+
if (H->buffered) {
251+
if (mysql_stmt_store_result(S->stmt)) {
252+
pdo_mysql_error_stmt(stmt);
253+
PDO_DBG_RETURN(0);
254+
}
255+
}
256+
}
257+
#endif
183258

184259
pdo_mysql_stmt_set_row_count(stmt);
185260
return true;
186261
}
187-
#endif
188262

189263
#ifndef PDO_USE_MYSQLND
190264
static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt) /* {{{ */
191265
{
192266
pdo_mysql_stmt *S = stmt->driver_data;
193-
pdo_mysql_db_handle *H = S->H;
194267

195268
PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_libmysql");
196269

@@ -207,86 +280,7 @@ static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt) /* {{{ */
207280
PDO_DBG_RETURN(0);
208281
}
209282

210-
if (!S->result) {
211-
int i;
212-
213-
/* figure out the result set format, if any */
214-
S->result = mysql_stmt_result_metadata(S->stmt);
215-
if (S->result) {
216-
int calc_max_length = H->buffered && S->max_length == 1;
217-
S->fields = mysql_fetch_fields(S->result);
218-
219-
php_pdo_stmt_set_column_count(stmt, (int)mysql_num_fields(S->result));
220-
S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
221-
S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
222-
S->out_length = ecalloc(stmt->column_count, sizeof(zend_ulong));
223-
224-
/* summon memory to hold the row */
225-
for (i = 0; i < stmt->column_count; i++) {
226-
if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
227-
my_bool on = 1;
228-
mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
229-
calc_max_length = 0;
230-
}
231-
switch (S->fields[i].type) {
232-
case FIELD_TYPE_INT24:
233-
S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
234-
break;
235-
case FIELD_TYPE_LONG:
236-
S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
237-
break;
238-
case FIELD_TYPE_LONGLONG:
239-
S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
240-
break;
241-
case FIELD_TYPE_TINY:
242-
S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
243-
break;
244-
case FIELD_TYPE_SHORT:
245-
S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
246-
break;
247-
default:
248-
S->bound_result[i].buffer_length =
249-
S->fields[i].max_length? S->fields[i].max_length:
250-
S->fields[i].length;
251-
/* work-around for longtext and alike */
252-
if (S->bound_result[i].buffer_length > H->max_buffer_size) {
253-
S->bound_result[i].buffer_length = H->max_buffer_size;
254-
}
255-
}
256-
257-
/* there are cases where the length reported by mysql is too short.
258-
* eg: when describing a table that contains an enum column. Since
259-
* we have no way of knowing the true length either, we'll bump up
260-
* our buffer size to a reasonable size, just in case */
261-
if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
262-
S->bound_result[i].buffer_length = 128;
263-
}
264-
265-
S->out_length[i] = 0;
266-
267-
S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
268-
S->bound_result[i].is_null = &S->out_null[i];
269-
S->bound_result[i].length = &S->out_length[i];
270-
S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
271-
}
272-
273-
if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
274-
pdo_mysql_error_stmt(stmt);
275-
PDO_DBG_RETURN(0);
276-
}
277-
278-
/* if buffered, pre-fetch all the data */
279-
if (H->buffered) {
280-
if (mysql_stmt_store_result(S->stmt)) {
281-
pdo_mysql_error_stmt(stmt);
282-
PDO_DBG_RETURN(0);
283-
}
284-
}
285-
}
286-
}
287-
288-
pdo_mysql_stmt_set_row_count(stmt);
289-
PDO_DBG_RETURN(1);
283+
PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
290284
}
291285
/* }}} */
292286
#endif
@@ -349,20 +343,15 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
349343
S->done = 1;
350344
PDO_DBG_RETURN(0);
351345
}
346+
PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
352347
} else {
353348
if (mysql_next_result(H->server)) {
354349
pdo_mysql_error_stmt(stmt);
355350
S->done = 1;
356351
PDO_DBG_RETURN(0);
357352
}
353+
PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt));
358354
}
359-
360-
#ifdef PDO_USE_MYSQLND
361-
if (S->stmt) {
362-
PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
363-
}
364-
#endif
365-
PDO_DBG_RETURN(pdo_mysql_fill_stmt_from_result(stmt));
366355
}
367356
/* }}} */
368357

ext/pdo_mysql/tests/pdo_mysql_multi_stmt_nextrowset.phpt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ $version = $matches[1] * 10000 + $matches[2] * 100 + $matches[3];
1515
if ($version < 50000)
1616
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
1717
$matches[1], $matches[2], $matches[3], $version));
18-
19-
if (!MySQLPDOTest::isPDOMySQLnd())
20-
die("skip This will not work with libmysql");
2118
?>
2219
--FILE--
2320
<?php

0 commit comments

Comments
 (0)