Вставка целочисленного массива с postgresql в C (libpq)

Я пытаюсь опубликовать целочисленный массив в моей базе данных postgresql. Я знаю, что я мог форматировать все как строку, а затем отправлять эту строку как одну команду SQL. Однако я считаю, что функция PQexecParams также должна помочь. Тем не менее, я как бы теряюсь, как использовать его.

//we need to convert the number into network byte order int val1 = 131; int val2 = 2342; int val3[5] = { 0, 7, 15, 31, 63 }; //set the values to use const char *values[3] = { (char *) &val1, (char *) &val2, (char *) val3 }; //calculate the lengths of each of the values int lengths[3] = { sizeof(val1), sizeof(val2), sizeof(val3) * 5 }; //state which parameters are binary int binary[3] = { 1, 1, 1 }; PGresult *res = PQexecParams(conn, "INSERT INTO family VALUES($1::int4, $2::int4, $3::INTEGER[])", 3, //number of parameters NULL, //ignore the Oid field values, //values to substitute $1 and $2 lengths, //the lengths, in bytes, of each of the parameter values binary, //whether the values are binary or not 0); //we want the result in text format 

Да, это скопировано из некоторого учебника. Однако это возвращает:

  ERROR: invalid array flags 

Использование обычного метода работает:

 PQexec(conn, "INSERT INTO family VALUES (2432, 31, '{0,1,2,3,4,5}')"); 

Вставляет данные просто отлично, и я тоже могу это прочесть.

Любая помощь будет принята с благодарностью! 🙂

libpq PQexecParams может принимать значения в текстовой или двоичной форме.

Для текстовых значений вы должны sprintf целое число в буфер, который вы помещаете в массив значений char** . Обычно это делается. Вы можете использовать текстовый формат с параметрами запроса, нет особых причин для возврата к интерполяции параметров в строку SQL самостоятельно.

Если вы хотите использовать передачи двоичного режима, вы должны убедиться, что целое число является правильным размером для целевого поля, находится в сетевом порядке байтов и что вы указали тип OID. Для этого используйте htonl (для uint32_t ) или htons (для uint16_t ). Прекрасно отменять подпись, поскольку вы просто переупорядочиваете байты.

Так:

  • Вы не можете игнорировать поле OID, если вы планируете использовать двоичную передачу
  • Используйте htonl , не заваривайте свой собственный порядок байтов
  • Конструкция массива values неверна. Вы помещаете char** s в массив char* и отбрасываете неправильный тип. Вы хотите &val1[0] или (эквивалент в большинстве / всех реализаций реального мира C, но не технически один и тот же для спецификации) просто val1 , а не (char*)&val1
  • Вы не можете предположить, что int32_t[] формат integer[] совпадает с int32_t[] . Вы должны передать тип OID INT4ARRAYOID (см. INT4ARRAYOID include/catalog/pg_type.h или select oid from pg_type where typname = '_int4' – внутреннее имя типа массива _ перед его базовым типом) и должно построить массив PostgreSQL значение, совместимое с функцией typreceive в pg_type для этого типа (которое является array_recv ), если вы собираетесь отправлять в двоичном режиме. В частности, массивы двоичного формата имеют заголовок . Вы не можете просто оставить заголовок.

Другими словами, код разбит несколькими захватывающими способами и не может работать так, как написано.

На самом деле, редко бывает полезно отправлять целые числа в двоичном режиме . Отправка текстового режима часто происходит быстрее, потому что он часто более компактен на проводе (небольшие значения). Если вы собираетесь использовать двоичный режим, вам нужно понять, как C представляет собой целые числа, как работает сетевой байт и порядок хоста, и т. Д.

Особенно при работе с массивами текстовый формат проще.

libpq может сделать это намного проще, чем в настоящее время, предлагая хорошие функции построения / декомпозиции массива как для текстовых, так и для двоичных массивов. Патчи, как всегда, приветствуются. В настоящее время сторонние библиотеки, такие как libpqtypes значительной степени заполняют эту роль.