291 lines
12 KiB
C
291 lines
12 KiB
C
/* -------------------------------------------------------------------------
|
|
*
|
|
* numeric_gs.h
|
|
* Definitions for the exact numeric data type of openGauss
|
|
*
|
|
* Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane.
|
|
*
|
|
* Copyright (c) 1998-2012, PostgreSQL Global Development Group
|
|
*
|
|
* src/include/utils/numeric_gs.h
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef _PG_NUMERIC_GS_H_
|
|
#define _PG_NUMERIC_GS_H_
|
|
|
|
#include "fmgr.h"
|
|
#include "vecexecutor/vectorbatch.h"
|
|
|
|
#define NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16))
|
|
#define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16))
|
|
|
|
#define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK)
|
|
#define NUMERIC_FLAGBITS_CHOICE(n) ((n)->n_header & NUMERIC_SIGN_MASK)
|
|
#define NUMERIC_NB_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_BI_MASK) // nan or biginteger
|
|
#define NUMERIC_NB_FLAGBITS_CHOICE(n) ((n)->n_header & NUMERIC_BI_MASK)
|
|
|
|
#define NUMERIC_IS_NAN(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_NAN)
|
|
#define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT)
|
|
#define NUMERIC_IS_SHORT_CHOICE(n) (NUMERIC_FLAGBITS_CHOICE(n) == NUMERIC_SHORT)
|
|
|
|
/*
|
|
* big integer macro
|
|
* determine the type of numeric
|
|
* verify whether a numeric data is NAN or BI by it's flag.
|
|
*/
|
|
#define NUMERIC_FLAG_IS_NAN(n) (n == NUMERIC_NAN)
|
|
#define NUMERIC_FLAG_IS_NANORBI(n) (n >= NUMERIC_NAN)
|
|
#define NUMERIC_FLAG_IS_BI(n) (n > NUMERIC_NAN)
|
|
#define NUMERIC_FLAG_IS_BI64(n) (n == NUMERIC_64)
|
|
#define NUMERIC_FLAG_IS_BI128(n) (n == NUMERIC_128)
|
|
|
|
/*
|
|
* big integer macro
|
|
* determine the type of numeric
|
|
* verify whether a numeric data is NAN or BI by itself.
|
|
*/
|
|
#define NUMERIC_IS_NANORBI(n) (NUMERIC_NB_FLAGBITS(n) >= NUMERIC_NAN)
|
|
#define NUMERIC_IS_NANORBI_CHOICE(n) (NUMERIC_NB_FLAGBITS_CHOICE(n) >= NUMERIC_NAN)
|
|
#define NUMERIC_IS_BI(n) (NUMERIC_NB_FLAGBITS(n) > NUMERIC_NAN)
|
|
#define NUMERIC_IS_BI64(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_64)
|
|
#define NUMERIC_IS_BI128(n) (NUMERIC_NB_FLAGBITS(n) == NUMERIC_128)
|
|
|
|
/*
|
|
* big integer macro
|
|
* the size of bi64 or bi128 is fixed.
|
|
* the size of bi64 is:
|
|
* 4 bytes(vl_len_) + 2 bytes(n_header) + 8 bytes(int64) = 14 bytes
|
|
* the size of bi128 is:
|
|
* 4 bytes(vl_len_) + 2 bytes(n_header) + 16 bytes(int128) = 22 bytes
|
|
*/
|
|
#define NUMERIC_64SZ (NUMERIC_HDRSZ_SHORT + sizeof(int64))
|
|
#define NUMERIC_128SZ (NUMERIC_HDRSZ_SHORT + sizeof(int128))
|
|
|
|
/*
|
|
* big integer macro
|
|
* get the scale of bi64 or bi128.
|
|
* scale = n_header & NUMERIC_BI_SCALEMASK
|
|
* get the value of bi64 or bi128
|
|
* convert NumericBi.n_data to int64 or int128 pointer, then
|
|
* assign value.
|
|
*/
|
|
#define NUMERIC_BI_SCALE(n) ((n)->choice.n_header & NUMERIC_BI_SCALEMASK)
|
|
#define NUMERIC_64VALUE(n) (*((int64*)((n)->choice.n_bi.n_data)))
|
|
|
|
/*
|
|
* If the flag bits are NUMERIC_SHORT or NUMERIC_NAN, we want the short header;
|
|
* otherwise, we want the long one. Instead of testing against each value, we
|
|
* can just look at the high bit, for a slight efficiency gain.
|
|
*/
|
|
#define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0)
|
|
#define NUMERIC_HEADER_IS_SHORT_CHOICE(n) (((n)->n_header & 0x8000) != 0)
|
|
#define NUMERIC_HEADER_SIZE(n) (VARHDRSZ + sizeof(uint16) + (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16)))
|
|
#define NUMERIC_HEADER_SIZE_CHOICE_1B(n) (VARHDRSZ_SHORT + sizeof(uint16) + (NUMERIC_HEADER_IS_SHORT_CHOICE(n) ? 0 : sizeof(int16)))
|
|
|
|
/*
|
|
* Short format definitions.
|
|
*/
|
|
#define NUMERIC_SHORT_SIGN_MASK 0x2000
|
|
#define NUMERIC_SHORT_DSCALE_MASK 0x1F80
|
|
#define NUMERIC_SHORT_DSCALE_SHIFT 7
|
|
#define NUMERIC_SHORT_DSCALE_MAX (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT)
|
|
#define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040
|
|
#define NUMERIC_SHORT_WEIGHT_MASK 0x003F
|
|
#define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK
|
|
#define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK + 1))
|
|
|
|
/*
|
|
* Extract sign, display scale, weight.
|
|
*/
|
|
#define NUMERIC_DSCALE_MASK 0x3FFF
|
|
|
|
#define NUMERIC_SIGN(n) \
|
|
(NUMERIC_IS_SHORT(n) \
|
|
? (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? NUMERIC_NEG : NUMERIC_POS) \
|
|
: NUMERIC_FLAGBITS(n))
|
|
#define NUMERIC_DSCALE(n) \
|
|
(NUMERIC_HEADER_IS_SHORT((n)) \
|
|
? ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) >> NUMERIC_SHORT_DSCALE_SHIFT \
|
|
: ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
|
|
#define NUMERIC_WEIGHT(n) \
|
|
(NUMERIC_HEADER_IS_SHORT((n)) \
|
|
? (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? ~NUMERIC_SHORT_WEIGHT_MASK : 0) | \
|
|
((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
|
|
: ((n)->choice.n_long.n_weight))
|
|
#define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? (num)->choice.n_short.n_data : (num)->choice.n_long.n_data)
|
|
#define NUMERIC_NDIGITS(num) ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit))
|
|
|
|
#define NUMERIC_SIGN_CHOICE(n) \
|
|
(NUMERIC_IS_SHORT_CHOICE(n) ? (((n)->n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? NUMERIC_NEG : NUMERIC_POS) \
|
|
: NUMERIC_FLAGBITS_CHOICE(n))
|
|
#define NUMERIC_DSCALE_CHOICE(n) \
|
|
(NUMERIC_HEADER_IS_SHORT_CHOICE((n)) ? ((n)->n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) >> NUMERIC_SHORT_DSCALE_SHIFT \
|
|
: ((n)->n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
|
|
#define NUMERIC_WEIGHT_CHOICE(n) \
|
|
(NUMERIC_HEADER_IS_SHORT_CHOICE((n)) ? (((n)->n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK \
|
|
? ~NUMERIC_SHORT_WEIGHT_MASK : 0) | ((n)->n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
|
|
: ((n)->n_long.n_weight))
|
|
#define NUMERIC_DIGITS_CHOICE(num) (NUMERIC_HEADER_IS_SHORT_CHOICE(num) ? (num)->n_short.n_data : (num)->n_long.n_data)
|
|
|
|
/*
|
|
* @Description: copy bi64 to ptr, this operation no need to allocate memory
|
|
* @IN ptr: the numeric pointer
|
|
* @IN value: the value of bi64
|
|
* @IN scale: the scale of bi64
|
|
*/
|
|
#define MAKE_NUMERIC64(ptr, value, scale) \
|
|
do { \
|
|
Numeric result = (Numeric)(ptr); \
|
|
SET_VARSIZE(result, NUMERIC_64SZ); \
|
|
result->choice.n_header = NUMERIC_64 + (scale); \
|
|
*((int64*)(result->choice.n_bi.n_data)) = (value); \
|
|
} while (0)
|
|
|
|
/*
|
|
* @Description: copy bi128 to ptr, this operation no need to allocate memory
|
|
* @IN ptr: the numeric pointer
|
|
* @IN value: the value of bi128
|
|
* @IN scale: the scale of bi128
|
|
*/
|
|
#define MAKE_NUMERIC128(ptr, value, scale) \
|
|
do { \
|
|
Numeric result = (Numeric)(ptr); \
|
|
SET_VARSIZE(result, NUMERIC_128SZ); \
|
|
result->choice.n_header = NUMERIC_128 + (scale); \
|
|
errno_t rc = EOK; \
|
|
rc = memcpy_s(result->choice.n_bi.n_data, sizeof(int128), (&value), sizeof(int128)); \
|
|
securec_check(rc, "\0", "\0"); \
|
|
} while (0)
|
|
|
|
/*
|
|
* the header size of short numeric is 6 bytes.
|
|
* the same to NUMERIC_HEADER_SIZE but for short numeric.
|
|
*/
|
|
#define SHORT_NUMERIC_HEADER_SIZE (VARHDRSZ + sizeof(uint16))
|
|
|
|
/*
|
|
* the same to NUMERIC_NDIGITS but for short numeric.
|
|
*/
|
|
#define SHORT_NUMERIC_NDIGITS(num) \
|
|
(AssertMacro(NUMERIC_IS_SHORT(num)), ((VARSIZE(num) - SHORT_NUMERIC_HEADER_SIZE) / sizeof(NumericDigit)))
|
|
|
|
/*
|
|
* the same to NUMERIC_DIGITS but for short numeric.
|
|
*/
|
|
#define SHORT_NUMERIC_DIGITS(num) (AssertMacro(NUMERIC_IS_SHORT(num)), (num)->choice.n_short.n_data)
|
|
|
|
/*
|
|
* @Description: allocate memory for bi64, and assign value to it
|
|
* @IN value: the value of bi64
|
|
* @IN scale: the scale of bi64
|
|
*/
|
|
inline Datum makeNumeric64(int64 value, uint8 scale, ScalarVector *arr = NULL)
|
|
{
|
|
Numeric result = NULL;
|
|
if (arr == NULL) {
|
|
result = (Numeric)palloc(NUMERIC_64SZ);
|
|
} else {
|
|
result = (Numeric)arr->m_buf->Allocate(NUMERIC_64SZ);
|
|
}
|
|
SET_VARSIZE(result, NUMERIC_64SZ);
|
|
result->choice.n_header = NUMERIC_64 + scale;
|
|
*((int64*)(result->choice.n_bi.n_data)) = value;
|
|
return (Datum)result;
|
|
}
|
|
|
|
/*
|
|
* @Description: allocate memory for bi128, and assign value to it
|
|
* @IN value: the value of bi128
|
|
* @IN scale: the scale of bi128
|
|
*/
|
|
inline Datum makeNumeric128(int128 value, uint8 scale, ScalarVector *arr = NULL)
|
|
{
|
|
Numeric result;
|
|
if (arr == NULL) {
|
|
result = (Numeric)palloc(NUMERIC_128SZ);
|
|
} else {
|
|
result = (Numeric)arr->m_buf->Allocate(NUMERIC_128SZ);
|
|
}
|
|
SET_VARSIZE(result, NUMERIC_128SZ);
|
|
result->choice.n_header = NUMERIC_128 + scale;
|
|
errno_t rc = EOK;
|
|
rc = memcpy_s(result->choice.n_bi.n_data, sizeof(int128), &value, sizeof(int128));
|
|
securec_check(rc, "\0", "\0") return (Datum)result;
|
|
}
|
|
|
|
/* Convert bi64 or bi128 to short numeric */
|
|
extern Numeric convert_int64_to_numeric(int64 data, uint8 scale);
|
|
extern Numeric convert_int128_to_numeric(int128 data, int scale);
|
|
|
|
/*
|
|
* @Description: convert bi64 or bi128 to numeric type
|
|
* @IN val: the bi64 or bi128 data
|
|
* @Return: the result of numeric type
|
|
*/
|
|
inline Numeric makeNumericNormal(Numeric val)
|
|
{
|
|
Assert(NUMERIC_IS_BI(val));
|
|
|
|
if (NUMERIC_IS_BI64(val)) {
|
|
return convert_int64_to_numeric(NUMERIC_64VALUE(val), NUMERIC_BI_SCALE(val));
|
|
}
|
|
|
|
else if (NUMERIC_IS_BI128(val)) {
|
|
int128 tmp_data = 0;
|
|
errno_t rc = EOK;
|
|
rc = memcpy_s(&tmp_data, sizeof(int128), val->choice.n_bi.n_data, sizeof(int128));
|
|
securec_check(rc, "\0", "\0");
|
|
return convert_int128_to_numeric(tmp_data, NUMERIC_BI_SCALE(val));
|
|
}
|
|
|
|
else {
|
|
elog(ERROR, "unrecognized big integer numeric format");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* @Description: Detoast column numeric data. Column numeric is
|
|
* a short-header type.
|
|
* @IN num: input numeric data
|
|
* @return: Numeric - detoast numeric data
|
|
*/
|
|
inline Numeric DatumGetBINumericShort(Datum num)
|
|
{
|
|
/*
|
|
* unlikely this is a short-header varlena --- convert to 4-byte header format
|
|
*/
|
|
struct varlena* new_attr = NULL;
|
|
struct varlena* old_attr = (struct varlena*)num;
|
|
Size data_size = VARSIZE_SHORT(old_attr) - VARHDRSZ_SHORT;
|
|
Size new_size = data_size + VARHDRSZ;
|
|
errno_t rc = EOK;
|
|
|
|
new_attr = (struct varlena*)palloc(new_size);
|
|
SET_VARSIZE(new_attr, new_size);
|
|
rc = memcpy_s(VARDATA(new_attr), new_size, VARDATA_SHORT(old_attr), data_size);
|
|
securec_check(rc, "", "");
|
|
old_attr = new_attr;
|
|
return (Numeric)old_attr;
|
|
}
|
|
|
|
/*
|
|
* @Description: Detoast column numeric data. Column numeric is unlikely
|
|
* a short-header type, simplify macro DatumGetNumeric
|
|
*
|
|
* @IN num: input numeric data
|
|
* @return: Numeric - detoast numeric data
|
|
*/
|
|
inline Numeric DatumGetBINumeric(Datum num)
|
|
{
|
|
if (likely(!VARATT_IS_SHORT(num))) {
|
|
return (Numeric)num;
|
|
} else {
|
|
return DatumGetBINumericShort(num);
|
|
}
|
|
}
|
|
|
|
#endif /* _PG_NUMERIC_GS_H_ */
|