Files
openGauss-server/src/include/utils/numeric_gs.h
2023-05-29 21:07:10 -07:00

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_ */