我try 将通过libpq以二进制格式查询的数据转换为C中的箭头格式.为此,我通过PQftype()查询了相应列的数据类型OID,并将它们与箭头数据类型匹配.但我不知道如何处理数字.

查询SELECT oid, typname FROM pg_type;返回1700表示数字,但如何获得精度和比例?

我无法在文档中找到有用的信息.我是不是找错地方了?

我可以从二进制数字的PGresult中得到什么?

提前感谢:)

EDIT

因此,在Laurenz的帮助下,我成功地将一个函数组合在一起,将二进制形式的数字从libpq转换为基本的字符串表示形式.当然,只有当您不打算将数字转换为字符串时,二进制结果才有意义,但它有助于理解数字的格式.

二进制形式基本上是由两个具有不同含义的字节整数组成的列表,数字整数只是以字符串形式串联在一起.这里是49273.64,二进制和字段中的精度为20,刻度为2:

ndigits | 00000000 | 00000011 | weight | 00000000 | 00000001 | sign | 00000000 | 00000000 | dscale | 00000000 | 00000010 | digits | 00000000 | 00000100 | 00100100 | 00111001 | 00011001 | 00000000 
ndigits: 3, weight: 1, sign: 0, dscale: 2, digits: 4 | 9273 | 6400
char *getStrFromNumeric(u_int16_t *numvar){
    u_int16_t ndigits = ntohs(numvar[0]); // how many u_int16_t at numvar[4]
    int16_t dscale = ntohs(numvar[3]); // how many char digits after decimal point
    int16_t weight = ntohs(numvar[1])+1; // weight+1 is how many u_int16_t from numvar[4] are before decimal point. here weight already gets +1 at initialization.
    char *result = (char *)malloc(sizeof(char)*(weight+dscale)+1+1+2); // +1+1 -> '\0' and '.'
    char *copyStr = (char *) malloc(sizeof (char)*5);
    int strindex = 0;
    int numvarindex = 0;
    while(weight>0){
        sprintf(copyStr, "%d", ntohs(numvar[numvarindex+4]));
        sprintf(&(result[strindex]), "%s", copyStr);
        strindex += strlen(copyStr);
        numvarindex++;
        weight--;
    }
    sprintf(&(result[strindex]), ".");
    strindex++;
    while(dscale>0){
        sprintf(copyStr, "%d", ntohs(numvar[numvarindex+4]));
        dscale -= strlen(copyStr);
        sprintf(&(result[strindex]), "%s", copyStr);
        strindex += strlen(copyStr);
        numvarindex++;
    }
    sprintf(&(result[strindex]), "\0");
    return result;
}

推荐答案

您可以在src/backend/utils/adt/numeric.c中找到实现细节.numeric的比例和精度不存储在pg_type中,因为它们不是数据类型的一部分.相关属性是pg_attribute中的atttypmod,因为比例和精度是列定义的一部分.

您可以从以下函数中收集在类型修饰符中对比例和精度进行编码的方式:

Datum
numerictypmodout(PG_FUNCTION_ARGS)
{
    int32       typmod = PG_GETARG_INT32(0);
    char       *res = (char *) palloc(64);

    if (typmod >= 0)
        snprintf(res, 64, "(%d,%d)",
                 ((typmod - VARHDRSZ) >> 16) & 0xffff,
                 (typmod - VARHDRSZ) & 0xffff);
    else
        *res = '\0';

    PG_RETURN_CSTRING(res);
}

因此,要获得表tn列的精度和比例,可以运行

SELECT (atttypmod - 4) >> 16 & 65535 AS precision,
       (atttypmod - 4) & 65535 AS scale
FROM pg_attribute
WHERE attrelid = 't'::regclass
  AND attname = 'n';

numeric的二进制格式在函数numeric_send中定义:

Datum
numeric_send(PG_FUNCTION_ARGS)
{
    Numeric     num = PG_GETARG_NUMERIC(0);
    NumericVar  x;
    StringInfoData buf;
    int         i;

    init_var_from_num(num, &x);

    pq_begintypsend(&buf);

    pq_sendint16(&buf, x.ndigits);
    pq_sendint16(&buf, x.weight);
    pq_sendint16(&buf, x.sign);
    pq_sendint16(&buf, x.dscale);
    for (i = 0; i < x.ndigits; i++)
        pq_sendint16(&buf, x.digits[i]);

    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

NumericVar的文档中描述了各个零件:

/* ----------
 * NumericVar is the format we use for arithmetic.  The digit-array part
 * is the same as the NumericData storage format, but the header is more
 * complex.
 *
 * The value represented by a NumericVar is determined by the sign, weight,
 * ndigits, and digits[] array.  If it is a "special" value (NaN or Inf)
 * then only the sign field matters; ndigits should be zero, and the weight
 * and dscale fields are ignored.
 *
 * Note: the first digit of a NumericVar's value is assumed to be multiplied
 * by NBASE ** weight.  Another way to say it is that there are weight+1
 * digits before the decimal point.  It is possible to have weight < 0.
 *
 * buf points at the physical start of the palloc'd digit buffer for the
 * NumericVar.  digits points at the first digit in actual use (the one
 * with the specified weight).  We normally leave an unused digit or two
 * (preset to zeroes) between buf and digits, so that there is room to store
 * a carry out of the top digit without reallocating space.  We just need to
 * decrement digits (and increment weight) to make room for the carry digit.
 * (There is no such extra space in a numeric value stored in the database,
 * only in a NumericVar in memory.)
 *
 * If buf is NULL then the digit buffer isn't actually palloc'd and should
 * not be freed --- see the constants below for an example.
 *
 * dscale, or display scale, is the nominal precision expressed as number
 * of digits after the decimal point (it must always be >= 0 at present).
 * dscale may be more than the number of physically stored fractional digits,
 * implying that we have suppressed storage of significant trailing zeroes.
 * It should never be less than the number of stored digits, since that would
 * imply hiding digits that are present.  NOTE that dscale is always expressed
 * in *decimal* digits, and so it may correspond to a fractional number of
 * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits.
 *
 * rscale, or result scale, is the target precision for a computation.
 * Like dscale it is expressed as number of *decimal* digits after the decimal
 * point, and is always >= 0 at present.
 * Note that rscale is not stored in variables --- it's figured on-the-fly
 * from the dscales of the inputs.
 *
 * While we consistently use "weight" to refer to the base-NBASE weight of
 * a numeric value, it is convenient in some scale-related calculations to
 * make use of the base-10 weight (ie, the approximate log10 of the value).
 * To avoid confusion, such a decimal-units weight is called a "dweight".
 *
 * NB: All the variable-level functions are written in a style that makes it
 * possible to give one and the same variable as argument and destination.
 * This is feasible because the digit buffer is separate from the variable.
 * ----------
 */

为了方便地处理numeric的二进制表示,应该使用libpgtypes library.

C++相关问答推荐

初始化char数组-用于初始化数组的字符串是否除了存储数组的位置之外单独存储在内存中

C strlen on char array

如何使用Python C API实现多线程程序?

空指针的运行时强制转换

在 struct 中强制转换空指针

错误:包含文件时类型名称未知

将 struct 传递给函数

在每种If-Else情况下执行语句的最佳方式

为什么我可以在GCC的标签后声明变量,但不能声明Clang?

有什么方法可以将字符串与我们 Select 的子字符串分开吗?喜欢:SIN(LOG(10))

在另一个函数中使用realloc和指针指向指针

C I/O:在Windows控制台上处理键盘输入

使用nmake for程序比Hello World稍微复杂一些

C语言中的数字指针

当我用scanf(&Q;%S%S%S&Q;,单词0,单词1,单词2)输入多个单词时,除了最后一个单词外,每个单词的第一个字符都丢失了

通过对一个大的Malloc内存进行切片来使用Malloc的内存片

为什么我无法访问C语言中的文件

如何在C中计算包含递增和递减运算符的逻辑表达式?

SSE 向量与 Epsilon 的比较

如何在 C 中编辑 struct 体中的多个变量