【问题标题】:How to insert text array in PostgreSQL table in binary format using libpq?如何使用 libpq 在 PostgreSQL 表中以二进制格式插入文本数组?
【发布时间】:2018-03-08 05:36:51
【问题描述】:

我没有找到任何描述如何在 PostgreSQL 中使用 libpq 处理二进制数组的文档。 所以你有桌子:

CREATE TABLE IF NOT EXISTS test_array ( array_column text[] )

您想使用PQexecParams 以二进制格式插入数组 这到底是怎么做到的?

【问题讨论】:

    标签: c++ c database postgresql libpq


    【解决方案1】:

    下面描述的所有内容都在 PostgreSQL 9.5 上进行了测试。

    PQexecParams 的原型如下:

    PGresult *PQexecParams(PGconn *conn,
                           const char *command,
                           int nParams,
                           const Oid *paramTypes,
                           const char * const *paramValues,
                           const int *paramLengths,
                           const int *paramFormats,
                           int resultFormat);
    

    https://www.postgresql.org/docs/current/static/libpq-exec.html

    Oid对于文本数组和其他类型可以在

    中找到

    /postgresql_sources_folder/src/include/catalog/pg_type.h

    在我们的例子中,我们需要 2 个:

    #define TEXTARRAYOID        1009
    #define TEXTOID         25
    

    外部PostgreSQL二进制数组的确切格式可以从函数推导出来:

    Datum array_send(PG_FUNCTION_ARGS);
    

    在这里定义:

    /postgresql_sources_folder/src/backend/utils/adt/arrayfuncs.c

    我在结构中描述格式:

    struct pgValsT {
      /* 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 */
      char dataBegin[];
    }__attribute__ ((__packed__));
    

    数组元素存储为结构:

    struct varlena
    {
      /* -1 if data = NULL */
      int32_t vl_len;
    
      /* our data */
      char vl_dat[];
    }__attribute__ ((__packed__));
    

    同样可以应用于以二进制格式检索数组。

    将二进制格式的文本数组插入相关表格的完整示例:

    #include <postgresql/libpq-fe.h>
    #include <arpa/inet.h>
    #include <cstdlib>
    #include <cstring>
    
    #define TEXTOID         25
    #define TEXTARRAYOID        1009
    
    
    int main(){
    
      PGconn* conn = PQsetdbLogin("localhost", "5432",
                     nullptr, nullptr, "my_database", "my_user",
                      "my_password");
    
      PGresult* res = NULL;
    
      /* our strings to pass as array. Sizes should exclude terminating '\0' 
         and be presented in network byte order */
    
      const char aStr1[] = "Stackoverflow";
      uint32_t pgSizeStr1 = ntohl(sizeof(aStr1) - 1);
    
      const char aStr2[] = "is";
      uint32_t pgSizeStr2 = ntohl(sizeof(aStr2) - 1);
    
      const char aStr3[] = "awesome!";
      uint32_t pgSizeStr3 = ntohl(sizeof(aStr3) - 1);
    
      /* number of parameters for PQexecParams. We need 1 for sending 1 text array */
      int nParams = 1;
    
      /* number of elements in array */
      int nElems = 3;
    
      /* our type is text array */
      Oid paramTypes[] = { TEXTARRAYOID };
    
      /* Allocating memory for our pgValsT structure + our data. Don't allocate memory for '\0' at the end of a string */
    
      uint32_t dataSize = sizeof(pgValsT) + sizeof(int32_t) * nElems + sizeof(aStr1) + sizeof(aStr2) + sizeof(aStr3) - nElems;
      void* vData = malloc(dataSize);
    
      pgValsT* pDataStruct = (pgValsT*)vData;
    
      /* setting up pointer to data to send to PostgreSQL */
      char* paramValues[] = { (char*)vData };
    
      /* setting up our element size */
      int paramLengths[] = { dataSize };
    
      /* setting binary format for our data */
      int paramFormats[] = { 1 };
    
      /* our array has one dimension */
      pDataStruct->ndims = ntohl(1);
    
      /* our array has no NULL elements */
      pDataStruct->hasNull = ntohl(0);
    
      /* type of our elements is text */
      pDataStruct->oidType = ntohl(TEXTOID);
    
      /* our array has 3 elements */
      pDataStruct->totalLen = ntohl(nElems);
    
      pDataStruct->subDims = ntohl(1);
    
    
      /* copy our strings and sizes to data structure excluding terminating '\0' */
      size_t byteOffset = 0;
      memcpy(pDataStruct->dataBegin, &pgSizeStr1, sizeof(pgSizeStr1));
      memcpy(pDataStruct->dataBegin + sizeof(pgSizeStr1), aStr1, sizeof(aStr1) - 1);
      byteOffset += sizeof(pgSizeStr1) + sizeof(aStr1) - 1;
    
      memcpy(pDataStruct->dataBegin + byteOffset, &pgSizeStr2, sizeof(pgSizeStr2));
      memcpy(pDataStruct->dataBegin + byteOffset + sizeof(pgSizeStr2), aStr2, sizeof(aStr2) - 1);
      byteOffset += sizeof(pgSizeStr2) + sizeof(aStr2) - 1;
    
    
      memcpy(pDataStruct->dataBegin + byteOffset, &pgSizeStr3, sizeof(pgSizeStr3));
      memcpy(pDataStruct->dataBegin + byteOffset + sizeof(pgSizeStr3), aStr3, sizeof(aStr3) - 1);
    
      /* executing query */
      res = PQexecParams(conn, "INSERT INTO test_array (array_column) values ($1)", 1, paramTypes, paramValues, paramLengths, paramFormats, 1);
    
      PQfinish(conn);
      PQclear(res);
      free(vData);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-21
      • 2010-11-20
      • 1970-01-01
      • 2021-08-12
      • 2013-12-14
      • 2017-09-21
      • 1970-01-01
      相关资源
      最近更新 更多