Как вставить массив байтов в таблицу PostgreSQL через libpq C++ API

пытаюсь обновить таблицу

CREATE TABLE some_table
(
    id integer NOT NULL,
    client_fid bigint NOT NULL,
    index bytea[],
    update_time timestamp without time zone
)
WITH (
    OIDS = FALSE

используя модифицированный код, вырезанный отсюда Как вставить текстовый массив в таблицу PostgreSQL в двоичном формате с помощью libpq?

#define BYTEAARRAYOID 1001
#define BYTEAOID 17

Вот определение структуры pgvals_t

struct pgvals_t
{
    /* number of array dimensions */
    int32_t ndims;
    /* flag describing if array has NULL values */
    int32_t hasNull;
    /* Oid of data stored in array. In our case is 25 for TEXT */
    Oid oidType;
    /* Number of elements in array */
    int32_t totalLen;
    /* Not sure for this one. 
     I think it describes dimensions of elements in case of arrays storing arrays */
    int32_t subDims;

    /* Here our data begins */

} __attribute__ ((__packed__));

Я удалил указатель dataBegins из структуры, так как он влияет на расположение данных в меморандуме.

std::size_t nElems = _data.size();
        uint32_t valsDataSize = sizeof(prx::pgvals_t) + sizeof(int32_t) * nElems +
                            sizeof(uint8_t)*nElems;

        void *pData = malloc(valsDataSize);
        prx::pgvals_t* pvals = (prx::pgvals_t*)pData;
        /* our array has one dimension */
        pvals->ndims = ntohl(1);
        /* our array has no NULL elements */
        pvals->hasNull = ntohl(0);
        /* type of our elements is bytea */
        pvals->oidType = ntohl(BYTEAOID);
        /* our array has nElems elements */
        pvals->totalLen = ntohl(nElems);
        pvals->subDims = ntohl(1);

        int32_t elemLen = ntohl(sizeof(uint8_t));
        std::size_t offset = sizeof(elemLen) + sizeof(_data[0]);
        char * ptr = (char*)(pvals + sizeof(prx::pgvals_t));
        for(auto byte : _data){

            memcpy(ptr, &elemLen, sizeof(elemLen));
            memcpy(ptr + sizeof(elemLen), &byte, sizeof(byte));
            ptr += offset;
        }

        Oid paramTypes[] = { BYTEAARRAYOID };

        char * paramValues[] = {(char* )pData};
        int paramLengths[] =  { (int)valsDataSize };
        int paramFormats[] = {1};
        PGresult *res = PQexecParams(m_conn, _statement.c_str(),
            1,             
            paramTypes,
            paramValues,
            paramLengths,
            paramFormats,
            1
        );
        if (PQresultStatus(res) != PGRES_COMMAND_OK) {
            std::string errMsg = PQresultErrorMessage(res);
            PQclear(res);
        throw std::runtime_error(errMsg);
    }
    free(pData);

Двоичные данные содержатся в переменной std::vector, и я использую следующий запрос в переменной _statement типа std::string

INSERT INTO some_table \
(id, client_id, \"index\", update_time) \
VALUES \
 (1, 2, $1, NOW())

Теперь после вызова PQExecParams я получаю исключение с сообщением "неправильный формат двоичных данных в параметре связывания 1"

В чем здесь может быть проблема?


person Eugene Kotyashov    schedule 27.02.2019    source источник
comment
использование модифицированного кода, взятого отсюда — сборка кода из разных источников без действительного понимания того, что делает код/что он делает, редко заканчивается хорошо. Просто говорю.   -  person Jesper Juhl    schedule 27.02.2019


Ответы (1)