numeric.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,840 行 · 第 1/5 页
C
2,840 行
result = 1; /* NAN > non-NAN */ } else if (NUMERIC_IS_NAN(num2)) { result = -1; /* non-NAN < NAN */ } else { result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1), num1->n_weight, NUMERIC_SIGN(num1), NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2), num2->n_weight, NUMERIC_SIGN(num2)); } return result;}Datumhash_numeric(PG_FUNCTION_ARGS){ Numeric key = PG_GETARG_NUMERIC(0); Datum digit_hash; Datum result; int weight; int start_offset; int end_offset; int i; int hash_len; /* If it's NaN, don't try to hash the rest of the fields */ if (NUMERIC_IS_NAN(key)) PG_RETURN_UINT32(0); weight = key->n_weight; start_offset = 0; end_offset = 0; /* * Omit any leading or trailing zeros from the input to the hash. The * numeric implementation *should* guarantee that leading and trailing * zeros are suppressed, but we're paranoid. Note that we measure the * starting and ending offsets in units of NumericDigits, not bytes. */ for (i = 0; i < NUMERIC_NDIGITS(key); i++) { if (NUMERIC_DIGITS(key)[i] != (NumericDigit) 0) break; start_offset++; /* * The weight is effectively the # of digits before the decimal point, * so decrement it for each leading zero we skip. */ weight--; } /* * If there are no non-zero digits, then the value of the number is zero, * regardless of any other fields. */ if (NUMERIC_NDIGITS(key) == start_offset) PG_RETURN_UINT32(-1); for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--) { if (NUMERIC_DIGITS(key)[i] != (NumericDigit) 0) break; end_offset++; } /* If we get here, there should be at least one non-zero digit */ Assert(start_offset + end_offset < NUMERIC_NDIGITS(key)); /* * Note that we don't hash on the Numeric's scale, since two numerics can * compare equal but have different scales. We also don't hash on the * sign, although we could: since a sign difference implies inequality, * this shouldn't affect correctness. */ hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset; digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset), hash_len * sizeof(NumericDigit)); /* Mix in the weight, via XOR */ result = digit_hash ^ weight; PG_RETURN_DATUM(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, true); 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); free_var(&result); free_var(&arg2); free_var(&arg1); PG_RETURN_NUMERIC(res);}/* * numeric_inc() - * * Increment a number by one */Datumnumeric_inc(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); NumericVar arg; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Compute the result and return it */ init_var(&arg); set_var_from_num(num, &arg); add_var(&arg, &const_one, &arg); res = make_result(&arg); free_var(&arg); PG_RETURN_NUMERIC(res);}/* * numeric_smaller() - * * Return the smaller of two numbers */Datumnumeric_smaller(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); /* * Use cmp_numerics so that this will agree with the comparison operators, * particularly as regards comparisons involving NaN. */ if (cmp_numerics(num1, num2) < 0) PG_RETURN_NUMERIC(num1); else PG_RETURN_NUMERIC(num2);}/* * numeric_larger() - * * Return the larger of two numbers */Datumnumeric_larger(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); /* * Use cmp_numerics so that this will agree with the comparison operators, * particularly as regards comparisons involving NaN. */ if (cmp_numerics(num1, num2) > 0) PG_RETURN_NUMERIC(num1); else PG_RETURN_NUMERIC(num2);}/* ---------------------------------------------------------------------- * * Advanced math functions * * ---------------------------------------------------------------------- *//* * numeric_fac() * * Compute factorial */Datumnumeric_fac(PG_FUNCTION_ARGS){ int64 num = PG_GETARG_INT64(0); Numeric res; NumericVar fact; NumericVar result; if (num <= 1) { res = make_result(&const_one); PG_RETURN_NUMERIC(res); } /* Fail immediately if the result would overflow */ if (num > 32177) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value overflows numeric format"))); init_var(&fact); init_var(&result); int8_to_numericvar(num, &result); for (num = num - 1; num > 1; num--) { /* this loop can take awhile, so allow it to be interrupted */ CHECK_FOR_INTERRUPTS(); int8_to_numericvar(num, &fact); mul_var(&result, &fact, &result, 0); } res = make_result(&result); free_var(&fact); free_var(&result); PG_RETURN_NUMERIC(res);}/* * numeric_sqrt() - * * Compute the square root of a numeric. */Datumnumeric_sqrt(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar arg; NumericVar result; int sweight; int rscale; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the argument and determine the result scale. We choose a scale * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any * case not less than the input's dscale. */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); /* Assume the input was normalized, so arg.weight is accurate */ sweight = (arg.weight + 1) * DEC_DIGITS / 2 - 1; rscale = NUMERIC_MIN_SIG_DIGITS - sweight; rscale = Max(rscale, arg.dscale); rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE); rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE); /* * Let sqrt_var() do the calculation and return the result. */ sqrt_var(&arg, &result, rscale); res = make_result(&result); free_var(&result); free_var(&arg); PG_RETURN_NUMERIC(res);}/* * numeric_exp() - * * Raise e to the power of x */Datumnumeric_exp(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar arg; NumericVar result; int rscale; double val; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Unpack the argument and determine the result scale. We choose a scale * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any * case not less than the input's dscale. */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); /* convert input to float8, ignoring overflow */ val = numericvar_to_double_no_overflow(&arg); /* * log10(result) = num * log10(e), so this is approximately the decimal * weight of the result: */ val *= 0.434294481903252; /* limit to something that won't cause integer overflow */ val = Max(val, -NUMERIC_MAX_RESULT_SCALE); val = Min(val, NUMERIC_MAX_RESULT_SCALE); rscale = NUMERIC_MIN_SIG_DIGITS - (int) val; rscale = Max(rscale, arg.dscale); rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE); rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE); /* * Let exp_var() do the calculation and return the result. */ exp_var(&arg, &result, rscale); res = make_result(&result); free_var(&result); free_var(&arg);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?