Libpq в PostgreSQL: кодирование для двоичного транспорта ARRAY [] - данных? - PullRequest
9 голосов
/ 25 октября 2010

после нескольких часов документации / досок / списков рассылки и без прогресса я могу спросить вас: как мне «кодировать» мои данные, чтобы использовать их для бинарного транспорта, используя libpq PQexecParams(.)?

Простые переменные только впорядковый номер с прямым порядком байтов:

PGconn *conn;
PGresult *res;
char *paramValues[1];
int paramLengths[1];
int paramFormats[1];

conn = PQconnectdb(CONNINFO);

// -- (1) -- send a float value
float val_f = 0.12345678901234567890; // float precision: ~7 decimal digits
// alloc some memory & write float (in big endian) into
paramValues[0] = (char *) malloc(sizeof(val_f));
*((uint32_t*) paramValues[0]) = htobe32(*((uint32_t*) &val_f)); // host to big endian

paramLengths[0] = sizeof(val_f);
paramFormats[0] = 1; // binary

res = PQexecParams(conn, "SELECT $1::real ;", //
        1, // number parameters
        NULL, // let the backend deduce param type
        paramValues, //
        paramLengths, //
        paramFormats, //
        0); // return text
printf("sent float: %s \n", PQgetvalue(res, 0, 0));
// --> sent float: 0.123457

и тому подобное: double, int и т.д ...

Но как насчет массивов?

    float vals_f[] = {1.23, 9.87};
    // alloc some memory
    paramValues[0] = (char *) malloc(sizeof(float) * 2);

//  ???? paramValues[0] = ??????

    paramLengths[0] = sizeof(float) * 2;
    paramFormats[0] = 1; // binary


    res = PQexecParams(conn, "SELECT $1::real[] ;", //
            1, // number parameters
            NULL, // let the backend deduce param type
            paramValues, //
            paramLengths, //
            paramFormats, //
            0); // return text
    printf("sent float array: %s \n", PQgetvalue(res, 0, 0));

Есть ли какой-нибудь рабочий пример?передачи данных ARRAY в двоичном формате PostgreSQL?Код в backend/utils/adt/ мне мало помогает (за исключением того, что теперь я знаю, что есть ARRAYTYPE, но не знаю, как их использовать): - (

Мне просто нужна функция char* to_PQbin(float [] input, int length) для перехода к paramValues[.] ...

Большое спасибо, Тебас

PS: Каков рекомендуемый способ преобразования простых переменных (вместо моих htobe32(.))?

Ответы [ 2 ]

9 голосов
/ 28 января 2011

http://git.postgresql.org/gitweb?p=postgresql.git;a=blob;f=src/include/utils/array.h;h=7f7e744cb12bc872f628f90dad99dfdf074eb314;hb=master описывает двоичный формат Postgres для массивов.При использовании libpq пропустите часть vl_len_.Например, массив из 4 целых чисел будет выглядеть следующим образом:

0x00000001 0x00000000 0x00000017 0x00000004 0x00000001 0x00000004 0x00000004 0x00000004 0x00000004

Это имеет OID 1007 (INT4ARAY).Первое целое число равно 1 измерению, второе целое число не является битовой картой NULL (поэтому ни одно из значений массива не равно NULL), третье целое число является OID элементов (23, INT4OID), четвертое целое число показывает, насколько велико первое измерение.(4) пятое целое число является начальным индексом первого измерения.После этого это необработанные данные массива в последовательном порядке, каждый элемент имеет префикс его длины (4 байта на каждое целое число).

5 голосов
/ 12 июля 2011

Как уже упоминалось ccuter , вам нужно создать свой собственный API.Следующий код извлекает одномерный массив int4, игнорирующий любые значения NULL.

#define   INT4OID   23

/*! Structure of array header to determine array type */
struct array_int4 {
  int32_t ndim; /* Number of dimensions */
  int32_t _ign; /* offset for data, removed by libpq */
  Oid elemtype; /* type of element in the array */

  /* First dimension */
  int32_t size; /* Number of elements */
  int32_t index; /* Index of first element */
  int32_t first_value; /* Beginning of integer data */
};

static int extract_int4_array (char *raw_array, 
                               int32_t **values, 
                               int *num_values) {
  /* Array information header */
  struct array_int4 *array = (struct array_int4 *) raw_array; 
  /* Pointer to traverse int array */
  int32_t *p_value = &(array->first_value);
  /* int value in host byte order */
  int32_t hval;

  /* Check if we have a 1-dimensional INT4 array */
  if (ntohl(array->ndim) != 1 
  || ntohl(array->elemtype) != INT4OID) {
    return -1;
  }
  /* Number of elements including NULLs */
  int array_elements = ntohl (array->size);

  *num_values = 0;
  /* Get size of array */
  for (int i=0; i<array_elements; ++i) {
    /* Check size to see if this is a NULL value */
    hval = ntohl (*p_value);
    if (hval != -1) {
      ++p_value;
      (*num_values) += 1;
    } 

    ++p_value;
  }
  *values = malloc (*num_values * sizeof **values);

  /* Fill output int array. Skip every other value as it contains the size of 
   * the element */
  *num_values = 0; /* Use num_values as the index of the output array */
  p_value = &(array->first_value);
  for (int i=0; i<array_elements; ++i) {
    /* Check size to see if this is a NULL value */
    hval = ntohl (*p_value);
    if (hval != -1) {
      ++p_value;
  (*values)[*num_values] = ntohl (*p_value);
      (*num_values) += 1;
    } 

    ++p_value;
  }

  return 0;
}

Также существует библиотека с именем libpqtypes , которая помогает для такого родапреобразование.

...