Spec-Zone.ru › MySQL Connectors 1.0

3.6.5 Поддержка подготовленных заявлений CALL

В этом разделе описывается поддержка подготовленных заявлений в C API для хранимых процедур, выполняемых с помощью заявлений:

Хранимые процедуры, выполняемые с помощью подготовленных заявлений, могут использоваться следующим образом:

  • Хранимая процедура может генерировать любое количество наборов результатов. Количество столбцов и типы данных столбцов не должны быть одинаковыми для всех наборов результатов.

  • Конечные значения параметров OUT и INOUT доступны вызывающему приложению после возврата процедуры. Эти параметры возвращаются в виде дополнительного набора результатов с одной строкой после любых наборов результатов, сгенерированных самой процедурой. Строка содержит значения параметров OUT и INOUT в порядке их объявления в списке параметров процедуры.

    Дополнительную информацию об эффекте необработанных условий на параметры процедуры см. в .

Далее показано, как использовать эти возможности через C API для подготовленных заявлений. Чтобы использовать подготовленные заявления через и заявления, см. .

Приложение, выполняющее подготовленное заявление, должно использовать цикл, который извлекает результат, а затем вызывает mysql_stmt_next_result(), чтобы определить, есть ли ещё результаты. Результаты состоят из любых наборов результатов, сгенерированных хранимой процедурой, за которыми следует конечное значение статуса, указывающее, завершилась ли процедура успешно.

Если процедура имеет параметры OUT или INOUT, набор результатов, предшествующий конечному значению статуса, содержит их значения. Чтобы определить, содержит ли набор результатов значения параметров, проверьте, установлен ли бит SERVER_PS_OUT_PARAMS в члене server_status обработчика соединения MYSQL:

mysql->server_status & SERVER_PS_OUT_PARAMS

Следующий пример использует подготовленное заявление для выполнения хранимой процедуры, которая генерирует несколько наборов результатов и возвращает значения параметров вызывающей стороне с помощью параметров OUT и INOUT. Процедура принимает параметры всех трёх типов (IN, OUT, INOUT), отображает их начальные значения, присваивает новые значения, отображает обновлённые значения и возвращается. Поэтому ожидаемая возвращаемая информация от процедуры состоит из нескольких наборов результатов и конечного статуса:

  • Один набор результатов из , отображающий начальные значения параметров: 10, NULL, 30. (Параметру OUT присваивается значение вызывающей стороной, но ожидается, что это присвоение будет неэффективным: параметры OUT рассматриваются как NULL внутри процедуры, пока им не будет присвоено значение внутри самой процедуры.)

  • Один набор результатов из , отображающий изменённые значения параметров: 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 */
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: 3
Data: this result set is produced by the procedure
 val[0] = 10; val[1] = NULL; val[2] = 30;
Number of columns in result: 3
Data: this result set is produced by the procedure
 val[0] = 100; val[1] = 200; val[2] = 300;
Number of columns in result: 2
Data: 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);
  }
}

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/c-api-8.0-en/c-api-prepared-call-statements.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API