Spec-Zone .ru
спецификации, руководства, описания, API
|
Этот раздел описывает поддержку готового оператора в API C для хранимых процедур, выполняемых, используя CALL
операторы:
В MySQL 5.7 хранимые процедуры выполнили подготовленное использование CALL
операторы могут использоваться следующими способами:
Хранимая процедура может произвести любое число наборов результатов. Число столбцов и типы данных столбцов не должны быть тем же самым для всех наборов результатов.
Заключительные значения OUT
и INOUT
параметры доступны вызывающему приложению после возвратов процедуры. Эти параметры возвращаются как
дополнительный набор результатов единственной строки после любых наборов результатов, произведенных
процедурой непосредственно. Строка содержит значения OUT
и INOUT
параметры в порядке, в котором они объявляются в списке параметров
процедуры.
Следующее обсуждение показывает, как использовать эти возможности через API C для готовых операторов.
Использовать подготовленный CALL
операторы через PREPARE
и EXECUTE
операторы, см. Раздел
13.2.1,"CALL
Синтаксис".
Если приложение могло бы быть скомпилировано или выполнено в контексте, где версия MySQL, более старого чем
5.5.3, используется, готовится CALL
возможности многократных наборов результатов и OUT
или INOUT
параметры не могли бы быть доступными:
Для стороны клиента приложение не будет компилировать, если библиотеки не будут от MySQL 5.5.3 или выше (API-функция, и символы, представленные в той версии, не будут присутствовать).
Чтобы проверить во времени выполнения, что сервер является достаточно недавним, клиент может использовать этот тест:
if (mysql_get_server_version(mysql) < 50503){ fprintf(stderr, "Server does not support required CALL capabilities\n"); mysql_close(mysql); exit (1);}
Приложение, которое выполняет готовое CALL
оператор должен использовать цикл, который выбирает результат и затем вызывает mysql_stmt_next_result()
определить, есть ли больше результатов. Результаты
состоят из любых наборов результатов, произведенных хранимой процедурой, сопровождаемой значением окончательного
статуса, которое указывает ли процедура, завершенная успешно.
Если процедура имеет OUT
или INOUT
параметры, набор
результатов, предшествующий значению окончательного статуса, содержат свои значения. Чтобы определить, содержит
ли набор результатов значения параметра, протестируйте ли SERVER_PS_OUT_PARAMS
бит
устанавливается в server_status
элемент MYSQL
обработчик соединения:
mysql->server_status & SERVER_PS_OUT_PARAMS
Следующий пример использует готовое CALL
оператор, чтобы выполнить хранимую процедуру, которая производит многократные наборы результатов и это
обеспечивает значения параметра назад для вызывающей стороны посредством OUT
и
INOUT
параметры. Процедура берет параметры всех трех типов (IN
,
OUT
, INOUT
), выводит на экран их начальные значения,
присваивает новые значения, выводит на экран обновленные значения, и возвраты. Информация об ожидаемом доходе из
процедуры поэтому состоит из многократных наборов результатов и окончательного статуса:
Один набор результатов от a SELECT
это выводит на экран начальные значения параметра: 10
, NULL
, 30
. ( OUT
параметр присваивается, значение вызывающей стороной, но это присвоение, как ожидают, будет
неэффективно: OUT
параметры замечаются как NULL
в пределах процедуры пока не присвоено значение в пределах
процедуры.)
Один набор результатов от a SELECT
это выводит на экран измененные значения параметра: 100
, 200
, 300
.
Один набор результатов, содержащий финал OUT
и INOUT
значения параметра: 200
, 300
.
Пакет окончательного статуса.
Код, чтобы выполнить процедуру:
MYSQL_STMT *stmt;MYSQL_BIND ps_params[3]; /* input parameter buffers */int int_data[3]; /* input/output values */my_bool is_null[3]; /* output value nullability */int status;/* set up stored procedure */status = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");test_error(mysql, status);status = mysql_query(mysql, "CREATE PROCEDURE p1(" " IN p_in INT, " " OUT p_out INT, " " INOUT p_inout INT) " "BEGIN " " SELECT p_in, p_out, p_inout; " " SET p_in = 100, p_out = 200, p_inout = 300; " " SELECT p_in, p_out, p_inout; " "END");test_error(mysql, status);/* initialize and prepare CALL statement with parameter placeholders */stmt = mysql_stmt_init(mysql);if (!stmt){ printf("Could not initialize statement\n"); exit(1);}status = mysql_stmt_prepare(stmt, "CALL p1(?, ?, ?)", 16);test_stmt_error(stmt, status);/* initialize parameters: p_in, p_out, p_inout (all INT) */memset(ps_params, 0, sizeof (ps_params));ps_params[0].buffer_type = MYSQL_TYPE_LONG;ps_params[0].buffer = (char *) &int_data[0];ps_params[0].length = 0;ps_params[0].is_null = 0;ps_params[1].buffer_type = MYSQL_TYPE_LONG;ps_params[1].buffer = (char *) &int_data[1];ps_params[1].length = 0;ps_params[1].is_null = 0;ps_params[2].buffer_type = MYSQL_TYPE_LONG;ps_params[2].buffer = (char *) &int_data[2];ps_params[2].length = 0;ps_params[2].is_null = 0;/* bind parameters */status = mysql_stmt_bind_param(stmt, ps_params);test_stmt_error(stmt, status);/* assign values to parameters and execute statement */int_data[0]= 10; /* p_in */int_data[1]= 20; /* p_out */int_data[2]= 30; /* p_inout */status = mysql_stmt_execute(stmt);test_stmt_error(stmt, status);/* process results until there are no more */do { int i; int num_fields; /* number of columns in result */ MYSQL_FIELD *fields; /* for result set metadata */ MYSQL_BIND *rs_bind; /* for output buffers */ /* the column count is > 0 if there is a result set */ /* 0 if the result is only the final status packet */ num_fields = mysql_stmt_field_count(stmt); if (num_fields > 0) { /* there is a result set to fetch */ printf("Number of columns in result: %d\n", (int) num_fields); /* what kind of result set is this? */ printf("Data: "); if(mysql->server_status & SERVER_PS_OUT_PARAMS) printf("this result set contains OUT/INOUT parameters\n"); else printf("this result set is produced by the procedure\n"); MYSQL_RES *rs_metadata = mysql_stmt_result_metadata(stmt); test_stmt_error(stmt, rs_metadata == NULL); fields = mysql_fetch_fields(rs_metadata); rs_bind = (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields); if (!rs_bind) { printf("Cannot allocate output buffers\n"); exit(1); } memset(rs_bind, 0, sizeof (MYSQL_BIND) * num_fields); /* set up and bind result set output buffers */ for (i = 0; i < num_fields; ++i) { rs_bind[i].buffer_type = fields[i].type; rs_bind[i].is_null = &is_null[i]; switch (fields[i].type) { case MYSQL_TYPE_LONG: rs_bind[i].buffer = (char *) &(int_data[i]); rs_bind[i].buffer_length = sizeof (int_data); break; default: fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type); exit(1); } } status = mysql_stmt_bind_result(stmt, rs_bind); test_stmt_error(stmt, status); /* fetch and display result set rows */ while (1) { status = mysql_stmt_fetch(stmt); if (status == 1 || status == MYSQL_NO_DATA) break; for (i = 0; i < num_fields; ++i) { switch (rs_bind[i].buffer_type) { case MYSQL_TYPE_LONG: if (*rs_bind[i].is_null) printf(" val[%d] = NULL;", i); else printf(" val[%d] = %ld;", i, (long) *((int *) rs_bind[i].buffer)); break; default: printf(" unexpected type (%d)\n", rs_bind[i].buffer_type); } } printf("\n"); } mysql_free_result(rs_metadata); /* free metadata */ free(rs_bind); /* free output buffers */ } else { /* no columns = final status packet */ printf("End of procedure output\n"); } /* more results? -1 = no, >0 = error, 0 = yes (keep looking) */ status = mysql_stmt_next_result(stmt); if (status > 0) test_stmt_error(stmt, status);} while (status == 0);mysql_stmt_close(stmt);
Выполнение процедуры должно произвести следующий вывод:
Number of columns in result: 3Data: this result set is produced by the procedure val[0] = 10; val[1] = NULL; val[2] = 30;Number of columns in result: 3Data: this result set is produced by the procedure val[0] = 100; val[1] = 200; val[2] = 300;Number of columns in result: 2Data: this result set contains OUT/INOUT parameters val[0] = 200; val[1] = 300;End of procedure output
Код использует две служебных подпрограммы, test_error()
и test_stmt_error()
,
проверять на ошибки и оконечный после печати диагностической информации, если ошибка произошла:
static void test_error(MYSQL *mysql, int status){ if (status) { fprintf(stderr, "Error: %s (errno: %d)\n", mysql_error(mysql), mysql_errno(mysql)); exit(1); }}static void test_stmt_error(MYSQL_STMT *stmt, int status){ if (status) { fprintf(stderr, "Error: %s (errno: %d)\n", mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); exit(1); }}