to_number(): allow 'V' to divide by 10^(the number of digits)
authorBruce Momjian <bruce@momjian.us>
Tue, 6 Oct 2015 01:03:38 +0000 (21:03 -0400)
committerBruce Momjian <bruce@momjian.us>
Tue, 6 Oct 2015 01:03:38 +0000 (21:03 -0400)
to_char('V') already multiplied in a similar manner.

Report by Jeremy Lowery

doc/src/sgml/func.sgml
src/backend/utils/adt/formatting.c

index 897ed647798c11a4168b135daf9e0e88c1b8b935..f8d9e460937b3294880bb65327f6264085705c17 100644 (file)
@@ -6152,12 +6152,14 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
 
      <listitem>
       <para>
-       <literal>V</literal> effectively
+       <literal>V</literal> with <function>to_char</function>
        multiplies the input values by
        <literal>10^<replaceable>n</replaceable></literal>, where
        <replaceable>n</replaceable> is the number of digits following
-       <literal>V</literal>.
-       <function>to_char</function> does not support the use of
+       <literal>V</literal>.  <literal>V</literal> with
+       <function>to_number</function> divides in a similar manner.
+       <function>to_char</function> and <function>to_number</function>
+       do not support the use of
        <literal>V</literal> combined with a decimal point
        (e.g., <literal>99.9V99</literal> is not allowed).
       </para>
index 5b09de32efc66d3ac07c559837ff101c45324f04..0a203f88991d128c5e787edc7e82183d3b62093a 100644 (file)
@@ -5055,7 +5055,7 @@ numeric_to_number(PG_FUNCTION_ARGS)
                                  VARSIZE(value) - VARHDRSZ, 0, 0, false, PG_GET_COLLATION());
 
        scale = Num.post;
-       precision = Max(0, Num.pre) + scale;
+       precision = Num.pre + Num.multi + scale;
 
        if (shouldFree)
                pfree(format);
@@ -5064,6 +5064,23 @@ numeric_to_number(PG_FUNCTION_ARGS)
                                                                 CStringGetDatum(numstr),
                                                                 ObjectIdGetDatum(InvalidOid),
                                          Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
+
+       if (IS_MULTI(&Num))
+       {
+               Numeric         x;
+               Numeric         a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
+                                                                                                        Int32GetDatum(10)));
+               Numeric         b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
+                                                                                         Int32GetDatum(-Num.multi)));
+
+               x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
+                                                                                               NumericGetDatum(a),
+                                                                                               NumericGetDatum(b)));
+               result = DirectFunctionCall2(numeric_mul,
+                                                                        result,
+                                                                        NumericGetDatum(x));
+       }
+
        pfree(numstr);
        return result;
 }