我嘗試將通過 libpq 查詢的二進制格式的資料轉換為 C 中的 Arrow 格式。為此,我通過 PQftype() 查詢了相應列的資料型別 Oids,并將它們與 Arrow 資料型別匹配。但我不確定如何處理數字。
查詢SELECT oid, typname FROM pg_type;為數字回傳 1700,但我如何獲得精度和比例?
我無法在檔案中找到有用的資訊。我在錯誤的地方搜索嗎? https://www.postgresql.org/docs/13/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL
我可以期望從二進制數字中得到什么?
提前致謝 :)
編輯
因此,在 Laurenz 的幫助下,我設法將一個函陣列合在一起,將二進制形式的數字從 libpq 轉換為基本的字串表示形式。當然,二進制結果只有在您不打算將數值轉換為字串時才有意義,但它有助于理解數值的格式。
二進制形式基本上是具有不同含義的 2 位元組整數串列,數字整數只是以它們的字串形式連接。這是 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;
}
uj5u.com熱心網友回復:
您可以在 中找到實作細節src/backend/utils/adt/numeric.c。的小數位數和精度numeric不存盤在 中pg_type,因為它們不是資料型別的一部分。相關屬性atttypmod在 中pg_attribute,因為比例和精度是列定義的一部分。
您可以收集在型別修飾符中編碼比例和精度的方式,例如從這個函式:
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);
}
n因此,要獲得表格列的精度和比例t,您可以運行
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庫。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/497551.html
標籤:C PostgreSQL 库
