3.6.3 Поддержка выполнения нескольких операторов
По умолчанию, mysql_real_query() и mysql_query() интерпретируют строку оператора как один оператор, который нужно выполнить, и вы обрабатываете результат в зависимости от того, создаёт ли оператор набор результатов (набор строк, как для ) или количество затронутых строк (как для , , и так далее).
MySQL также поддерживает выполнение строки, содержащей несколько операторов, разделённых точкой с запятой (;). Эта возможность активируется с помощью специальных опций, которые указываются либо при подключении к серверу с помощью mysql_real_connect(), либо после подключения, вызвав mysql_set_server_option().
Выполнение строки с несколькими операторами может привести к получению нескольких наборов результатов или показателей количества затронутых строк. Обработка этих результатов предполагает другой подход, чем в случае с одним оператором: после обработки результата первого оператора необходимо проверить, существуют ли другие результаты, и, если да, обработать их по очереди. Для поддержки обработки нескольких результатов в C API включены функции mysql_more_results() и mysql_next_result(). Эти функции используются в конце цикла, который повторяется, пока существуют дополнительные результаты. Несоблюдение этого способа обработки результатов может привести к разрыву соединения с сервером.
Обработка нескольких результатов также требуется, если вы выполняете операторы для хранимых процедур. Результаты хранимой процедуры имеют следующие характеристики:
-
Операторы внутри процедуры могут создавать наборы результатов (например, если она выполняет операторы). Эти наборы результатов возвращаются в том порядке, в котором они генерируются во время выполнения процедуры.
В общем случае вызывающая сторона не может знать, сколько наборов результатов вернёт процедура. Выполнение процедуры может зависеть от циклов или условных операторов, которые приводят к различному пути выполнения при каждом вызове. Поэтому вы должны быть готовы к получению нескольких результатов.
Конечным результатом процедуры является результат состояния, который не содержит набора результатов. Состояние указывает, выполнилась ли процедура успешно или произошла ошибка.
Возможности выполнения нескольких операторов и обработки нескольких результатов могут быть использованы только с mysql_real_query() или mysql_query(). Они не могут быть использованы с интерфейсом подготовленных операторов. Обработчики подготовленных операторов определены для работы только со строками, содержащими один оператор. См. Главу 6, Интерфейс подготовленных операторов C API.
Для включения выполнения нескольких операторов и обработки нескольких результатов можно использовать следующие опции:
-
Функция
mysql_real_connect()имеет аргументflags, для которого два значения опций являются релевантными:CLIENT_MULTI_RESULTSпозволяет программе-клиенту обрабатывать несколько результатов. Эта опция обязательна, если вы выполняете операторы для хранимых процедур, которые возвращают наборы результатов. В противном случае такие процедуры приводят к ошибкеError 1312 (0A000): PROCEDURE.proc_namecan't return a result set in the given contextCLIENT_MULTI_RESULTSвключена по умолчанию.CLIENT_MULTI_STATEMENTSпозволяетmysql_real_query()иmysql_query()выполнять строки операторов, содержащие несколько операторов, разделённых точками с запятой. Эта опция также подразумевает включениеCLIENT_MULTI_RESULTS, поэтому аргументflagsсо значениемCLIENT_MULTI_STATEMENTSдляmysql_real_connect()эквивалентен аргументуCLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS. То есть,CLIENT_MULTI_STATEMENTSдостаточно для включения выполнения нескольких операторов и обработки всех результатов.
После установления соединения с сервером вы можете использовать функцию
mysql_set_server_option(), чтобы включить или отключить выполнение нескольких операторов, передав ей аргументMYSQL_OPTION_MULTI_STATEMENTS_ONилиMYSQL_OPTION_MULTI_STATEMENTS_OFF. Включение выполнения нескольких операторов с помощью этой функции также включает обработку "простых" результатов для строки с несколькими операторами, где каждый оператор возвращает один результат, но этого недостаточно для обработки хранимых процедур, которые возвращают наборы результатов.
Следующая процедура описывает рекомендуемую стратегию обработки нескольких операторов:
Передайте
CLIENT_MULTI_STATEMENTSвmysql_real_connect(), чтобы полностью включить выполнение нескольких операторов и обработку нескольких результатов.После вызова
mysql_real_query()илиmysql_query()и проверки успешного выполнения, перейдите в цикл, в котором вы обрабатываете результаты операторов.Для каждой итерации цикла обработайте текущий результат оператора, получив либо набор результатов, либо количество затронутых строк. Если произошла ошибка, выйдите из цикла.
В конце цикла вызовите
mysql_next_result(), чтобы проверить, существует ли другой результат, и, если да, начать его получение. Если больше результатов нет, выйдите из цикла.
Один из возможных способов реализации описанной выше стратегии показан ниже. Последнюю часть цикла можно сократить до простого проверки, возвращает ли mysql_next_result() ненулевое значение. Приведённый код различает отсутствие результатов и ошибку, что позволяет вывести сообщение при последней ситуации.
/* connect to server with the CLIENT_MULTI_STATEMENTS option */
if (mysql_real_connect (mysql, host_name, user_name, password,
db_name, port_num, socket_name, CLIENT_MULTI_STATEMENTS) == NULL)
{
printf("mysql_real_connect() failed\n");
mysql_close(mysql);
exit(1);
}
/* execute multiple statements */
status = mysql_query(mysql,
"DROP TABLE IF EXISTS test_table;\
CREATE TABLE test_table(id INT);\
INSERT INTO test_table VALUES(10);\
UPDATE test_table SET id=20 WHERE id=10;\
SELECT * FROM test_table;\
DROP TABLE test_table");
if (status)
{
printf("Could not execute statement(s)");
mysql_close(mysql);
exit(0);
}
/* process each statement result */
do {
/* did current statement return data? */
result = mysql_store_result(mysql);
if (result)
{
/* yes; process rows and free the result set */
process_result_set(mysql, result);
mysql_free_result(result);
}
else /* no result set or error */
{
if (mysql_field_count(mysql) == 0)
{
printf("%lld rows affected\n",
mysql_affected_rows(mysql));
}
else /* some error occurred */
{
printf("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(mysql)) > 0)
printf("Could not execute statement\n");
} while (status == 0);
mysql_close(mysql);
© 2025 Oracle
Licensed under the GPLv2 License.