📄 numeric.c
字号:
else res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num); } PG_RETURN_NUMERIC(res);}Datumnumeric_uplus(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; res = (Numeric) palloc(num->varlen); memcpy(res, num, num->varlen); PG_RETURN_NUMERIC(res);}/* * numeric_sign() - * * returns -1 if the argument is less than 0, 0 if the argument is equal * to 0, and 1 if the argument is greater than zero. */Datumnumeric_sign(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar result; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); init_var(&result); /* * The packed format is known to be totally zero digit trimmed always. * So we can identify a ZERO by the fact that there are no digits at * all. */ if (num->varlen == NUMERIC_HDRSZ) set_var_from_var(&const_zero, &result); else { /* * And if there are some, we return a copy of ONE with the sign of * our argument */ set_var_from_var(&const_one, &result); result.sign = NUMERIC_SIGN(num); } res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_round() - * * Round a value to have 'scale' digits after the decimal point. * We allow negative 'scale', implying rounding before the decimal * point --- Oracle interprets rounding that way. */Datumnumeric_round(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); int32 scale = PG_GETARG_INT32(1); Numeric res; NumericVar arg; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Limit the scale value to avoid possible overflow in calculations */ scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE); scale = Min(scale, NUMERIC_MAX_RESULT_SCALE); /* * Unpack the argument and round it at the proper digit position */ init_var(&arg); set_var_from_num(num, &arg); round_var(&arg, scale); /* We don't allow negative output dscale */ if (scale < 0) arg.dscale = 0; /* * Return the rounded result */ res = make_result(&arg); free_var(&arg); PG_RETURN_NUMERIC(res);}/* * numeric_trunc() - * * Truncate a value to have 'scale' digits after the decimal point. * We allow negative 'scale', implying a truncation before the decimal * point --- Oracle interprets truncation that way. */Datumnumeric_trunc(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); int32 scale = PG_GETARG_INT32(1); Numeric res; NumericVar arg; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Limit the scale value to avoid possible overflow in calculations */ scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE); scale = Min(scale, NUMERIC_MAX_RESULT_SCALE); /* * Unpack the argument and truncate it at the proper digit position */ init_var(&arg); set_var_from_num(num, &arg); trunc_var(&arg, scale); /* We don't allow negative output dscale */ if (scale < 0) arg.dscale = 0; /* * Return the truncated result */ res = make_result(&arg); free_var(&arg); PG_RETURN_NUMERIC(res);}/* * numeric_ceil() - * * Return the smallest integer greater than or equal to the argument */Datumnumeric_ceil(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar result; if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); init_var(&result); set_var_from_num(num, &result); ceil_var(&result, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_floor() - * * Return the largest integer equal to or less than the argument */Datumnumeric_floor(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar result; if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); init_var(&result); set_var_from_num(num, &result); floor_var(&result, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}/* ---------------------------------------------------------------------- * * Comparison functions * * Note: btree indexes need these routines not to leak memory; therefore, * be careful to free working copies of toasted datums. Most places don't * need to be so careful. * ---------------------------------------------------------------------- */Datumnumeric_cmp(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); int result; result = cmp_numerics(num1, num2); PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_INT32(result);}Datumnumeric_eq(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) == 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}Datumnumeric_ne(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) != 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}Datumnumeric_gt(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) > 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}Datumnumeric_ge(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) >= 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}Datumnumeric_lt(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) < 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}Datumnumeric_le(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); bool result; result = cmp_numerics(num1, num2) <= 0; PG_FREE_IF_COPY(num1, 0); PG_FREE_IF_COPY(num2, 1); PG_RETURN_BOOL(result);}static intcmp_numerics(Numeric num1, Numeric num2){ int result; /* * We consider all NANs to be equal and larger than any non-NAN. This * is somewhat arbitrary; the important thing is to have a consistent * sort order. */ if (NUMERIC_IS_NAN(num1)) { if (NUMERIC_IS_NAN(num2)) result = 0; /* NAN = NAN */ else result = 1; /* NAN > non-NAN */ } else if (NUMERIC_IS_NAN(num2)) { result = -1; /* non-NAN < NAN */ } else { NumericVar arg1; NumericVar arg2; init_var(&arg1); init_var(&arg2); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); result = cmp_var(&arg1, &arg2); free_var(&arg1); free_var(&arg2); } return result;}/* ---------------------------------------------------------------------- * * Basic arithmetic functions * * ---------------------------------------------------------------------- *//* * numeric_add() - * * Add two numerics */Datumnumeric_add(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the values, let add_var() compute the result and return it. */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); add_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_sub() - * * Subtract one numeric from another */Datumnumeric_sub(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the values, let sub_var() compute the result and return it. */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); sub_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_mul() - * * Calculate the product of two numerics */Datumnumeric_mul(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the values, let mul_var() compute the result and return it. * Unlike add_var() and sub_var(), mul_var() will round its result. In * the case of numeric_mul(), which is invoked for the * operator on * numerics, we request exact representation for the product (rscale = * sum(dscale of arg1, dscale of arg2)). */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_div() - * * Divide one numeric into another */Datumnumeric_div(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; int rscale; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the arguments */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); /* * Select scale for division result */ rscale = select_div_scale(&arg1, &arg2); /* * Do the divide and return the result */ div_var(&arg1, &arg2, &result, rscale); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_mod() - * * Calculate the modulo of two numerics */Datumnumeric_mod(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); mod_var(&arg1, &arg2, &result); res = make_result(&result);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -