diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index a3e1942c7..dece4b43f 100644 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -511,6 +511,11 @@ AddFuncGroup( "bigint_tid", 1, AddBuiltinFunc(_0(3214), _1("bigint_tid"), _2(1), _3(true), _4(false), _5(bigint_tid), _6(27), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 20), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("bigint_tid"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "bin_to_num", 2, + AddBuiltinFunc(_0(971), _1("bin_to_num"), _2(1), _3(true), _4(false), _5(bin_to_num), _6(1700), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(0), _11(0), _12(1700), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 1231), _21(1,1231), _22(1,'v'), _23(NULL), _24(NULL), _25("bin_to_num"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("convert bits to number"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(1,1231)), + AddBuiltinFunc(_0(974), _1("bin_to_num"), _2(0), _3(false), _4(false), _5(bin_to_num_noparam), _6(1700), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(0), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("bin_to_num_noparam"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("convert bits to number"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "bit", 3, diff --git a/src/common/backend/utils/adt/numeric.cpp b/src/common/backend/utils/adt/numeric.cpp index 71748c0b8..83c58de86 100644 --- a/src/common/backend/utils/adt/numeric.cpp +++ b/src/common/backend/utils/adt/numeric.cpp @@ -7971,6 +7971,58 @@ Datum numtodsinterval(PG_FUNCTION_ARGS) CHECK_RETNULL_RETURN_DATUM(result); } +/* Convert binary array to number*/ +Datum bin_to_num(PG_FUNCTION_ARGS) +{ + int i; + Numeric arg; + double argD; + int32 argI; + Datum result = DirectFunctionCall1(int4_numeric, Int32GetDatum(0)); + + ArrayType* arr = PG_GETARG_ARRAYTYPE_P(0); + Datum *elemValues; + bool *elemNulls; + int elemCount; + deconstruct_array(arr, NUMERICOID, -1, false, 'i', &elemValues, &elemNulls, &elemCount); + + for (i = 0; i < elemCount; i++) { + if (elemNulls[i]) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("illegal argument for function"))); + } + arg = DatumGetNumeric(elemValues[i]); + argD = numeric_to_double_no_overflow(arg); + if (argD > INT32_MAX) { + argI = INT32_MAX; + } else if (argD < INT32_MIN) { + argI = INT32_MIN; + } else { + argI = (argD < 0) ? ceil(argD) : floor(argD); + } + + if (argI == 0) { + result = DirectFunctionCall2(numeric_add, result, result); + } else if (argI == 1) { + result = DirectFunctionCall2(numeric_add, result, result); + result = DirectFunctionCall1(numeric_inc, result); + } else { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("argument %d is out of range", argI))); + } + } + + PG_RETURN_DATUM(result); +} + +/* Convert binary array to number*/ +Datum bin_to_num_noparam(PG_FUNCTION_ARGS) +{ + PG_RETURN_NUMERIC(make_result(&const_zero)); +} + /* Convert numeric to interval */ Datum numeric_interval(PG_FUNCTION_ARGS) { diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index bad05f1c7..01b8966bf 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -77,7 +77,7 @@ bool will_shutdown = false; * ********************************************/ -const uint32 GRAND_VERSION_NUM = 93008; +const uint32 GRAND_VERSION_NUM = 93009; /******************************************** * 2.VERSION NUM FOR EACH FEATURE diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_93_009.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_93_009.sql new file mode 100644 index 000000000..fab37c7ee --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_93_009.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS pg_catalog.bin_to_num(VARIADIC bins numeric[]) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.bin_to_num() CASCADE; diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_93_009.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_93_009.sql new file mode 100644 index 000000000..fab37c7ee --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_93_009.sql @@ -0,0 +1,2 @@ +DROP FUNCTION IF EXISTS pg_catalog.bin_to_num(VARIADIC bins numeric[]) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.bin_to_num() CASCADE; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_93_009.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_93_009.sql new file mode 100644 index 000000000..67465b7d2 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_93_009.sql @@ -0,0 +1,6 @@ +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 971; +CREATE OR REPLACE FUNCTION pg_catalog.bin_to_num(VARIADIC bins numeric[]) +RETURNS numeric LANGUAGE INTERNAL VOLATILE STRICT as 'bin_to_num'; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 974; +CREATE OR REPLACE FUNCTION pg_catalog.bin_to_num() +RETURNS numeric LANGUAGE INTERNAL VOLATILE as 'bin_to_num_noparam'; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_93_009.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_93_009.sql new file mode 100644 index 000000000..67465b7d2 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_93_009.sql @@ -0,0 +1,6 @@ +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 971; +CREATE OR REPLACE FUNCTION pg_catalog.bin_to_num(VARIADIC bins numeric[]) +RETURNS numeric LANGUAGE INTERNAL VOLATILE STRICT as 'bin_to_num'; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 974; +CREATE OR REPLACE FUNCTION pg_catalog.bin_to_num() +RETURNS numeric LANGUAGE INTERNAL VOLATILE as 'bin_to_num_noparam'; diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index 3c82cec89..2821c4ef5 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -197,6 +197,8 @@ extern bool numeric_is_nan(Numeric num); int32 numeric_maximum_size(int32 typmod); extern char* numeric_out_sci(Numeric num, int scale); extern Datum numtodsinterval(PG_FUNCTION_ARGS); +extern Datum bin_to_num(PG_FUNCTION_ARGS); +extern Datum bin_to_num_noparam(PG_FUNCTION_ARGS); extern int cmp_numerics(Numeric num1, Numeric num2); extern int128 numeric_int16_internal(Numeric num); extern char* output_numeric_out(Numeric num); diff --git a/src/test/regress/expected/hw_functions.out b/src/test/regress/expected/hw_functions.out index 72e7ac77b..f4739b78c 100644 --- a/src/test/regress/expected/hw_functions.out +++ b/src/test/regress/expected/hw_functions.out @@ -396,6 +396,144 @@ from varlentype order by col_int; drop table type; drop table varlentype; drop table time; +-- test function bin_to_num +select bin_to_num(1,0,0); + bin_to_num +------------ + 4 +(1 row) + +select bin_to_num('1',0,0); + bin_to_num +------------ + 4 +(1 row) + +select bin_to_num('1',2-1,0); + bin_to_num +------------ + 6 +(1 row) + +select bin_to_num(NULL); +ERROR: illegal argument for function +CONTEXT: referenced column: bin_to_num +select bin_to_num(); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num('a','b'); +ERROR: invalid input syntax for type numeric: "a" +LINE 1: select bin_to_num('a','b'); + ^ +CONTEXT: referenced column: bin_to_num +select bin_to_num(-2.9); +ERROR: argument -2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-2.1); +ERROR: argument -2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-2.0); +ERROR: argument -2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-1.9); +ERROR: argument -1 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-1.1); +ERROR: argument -1 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-1.0); +ERROR: argument -1 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-0.9); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(-0.1); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(-0.0); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(0.0); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(0.1); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(0.9); + bin_to_num +------------ + 0 +(1 row) + +select bin_to_num(1.0); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(1.1); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(1.4); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(1.5); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(1.6); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(1.9); + bin_to_num +------------ + 1 +(1 row) + +select bin_to_num(2.0); +ERROR: argument 2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(2.1); +ERROR: argument 2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(2.9); +ERROR: argument 2 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(9999999999000); +ERROR: argument 2147483647 is out of range +CONTEXT: referenced column: bin_to_num +select bin_to_num(-9999999999000); +ERROR: argument -2147483648 is out of range +CONTEXT: referenced column: bin_to_num -- tests for repeat -- create table at first create table test_null_repeat(id int, col2 text); diff --git a/src/test/regress/output/pg_proc_test.source b/src/test/regress/output/pg_proc_test.source index 09411481c..1eda0cdf8 100644 --- a/src/test/regress/output/pg_proc_test.source +++ b/src/test/regress/output/pg_proc_test.source @@ -1,6 +1,7 @@ select provariadic,oid, proname from pg_proc where arraycontains(proargmodes::char[],ARRAY['v'::char]) order by oid; provariadic | oid | proname -------------+------+------------------------------------- + 1700 | 971 | bin_to_num 2276 | 3058 | concat 2276 | 3059 | concat_ws 1185 | 3119 | standby_statement_history @@ -26,7 +27,7 @@ select provariadic,oid, proname from pg_proc where arraycontains(proargmodes::ch 2276 | 7107 | db4ai_predict_by_numeric 2276 | 7108 | db4ai_predict_by_text 2276 | 7109 | db4ai_predict_by_float8_array -(25 rows) +(26 rows) select prokind,length(prokind),count(*) from pg_proc where oid < 16384 group by prokind; prokind | length | count diff --git a/src/test/regress/sql/hw_functions.sql b/src/test/regress/sql/hw_functions.sql index 57f948dda..7174e9bd2 100644 --- a/src/test/regress/sql/hw_functions.sql +++ b/src/test/regress/sql/hw_functions.sql @@ -178,6 +178,37 @@ drop table type; drop table varlentype; drop table time; +-- test function bin_to_num +select bin_to_num(1,0,0); +select bin_to_num('1',0,0); +select bin_to_num('1',2-1,0); +select bin_to_num(NULL); +select bin_to_num(); +select bin_to_num('a','b'); +select bin_to_num(-2.9); +select bin_to_num(-2.1); +select bin_to_num(-2.0); +select bin_to_num(-1.9); +select bin_to_num(-1.1); +select bin_to_num(-1.0); +select bin_to_num(-0.9); +select bin_to_num(-0.1); +select bin_to_num(-0.0); +select bin_to_num(0.0); +select bin_to_num(0.1); +select bin_to_num(0.9); +select bin_to_num(1.0); +select bin_to_num(1.1); +select bin_to_num(1.4); +select bin_to_num(1.5); +select bin_to_num(1.6); +select bin_to_num(1.9); +select bin_to_num(2.0); +select bin_to_num(2.1); +select bin_to_num(2.9); +select bin_to_num(9999999999000); +select bin_to_num(-9999999999000); + -- tests for repeat -- create table at first create table test_null_repeat(id int, col2 text);