]> granicus.if.org Git - postgresql/commitdiff
Try to fix portability issue in enum renumbering (again).
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Aug 2016 17:58:01 +0000 (13:58 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Aug 2016 17:58:01 +0000 (13:58 -0400)
The hack embodied in commit 4ba61a487 no longer works after today's change
to allow DatumGetFloat4/Float4GetDatum to be inlined (commit 14cca1bf8).
Probably what's happening is that the faulty compilers are deciding that
the now-inlined assignment is a no-op and so they're not required to
round to float4 width.

We had a bunch of similar issues earlier this year in the degree-based
trig functions, and eventually settled on using volatile intermediate
variables as the least ugly method of forcing recalcitrant compilers
to do what the C standard says (cf commit 82311bcdd).  Let's see if
that method works here.

Discussion: <4640.1472664476@sss.pgh.pa.us>

src/backend/catalog/pg_enum.c

index af89daa7128ee6274b669bc118a7d0bafa6c3d8a..c66f9632c29a3c36843d03df25a0059145a6841c 100644 (file)
@@ -315,21 +315,21 @@ restart:
                        newelemorder = nbr_en->enumsortorder + 1;
                else
                {
-                       other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
-                       newelemorder = (nbr_en->enumsortorder +
-                                                       other_nbr_en->enumsortorder) / 2;
-
                        /*
-                        * On some machines, newelemorder may be in a register that's
-                        * wider than float4.  We need to force it to be rounded to float4
-                        * precision before making the following comparisons, or we'll get
-                        * wrong results.  (Such behavior violates the C standard, but
-                        * fixing the compilers is out of our reach.)
+                        * The midpoint value computed here has to be rounded to float4
+                        * precision, else our equality comparisons against the adjacent
+                        * values are meaningless.  The most portable way of forcing that
+                        * to happen with non-C-standard-compliant compilers is to store
+                        * it into a volatile variable.
                         */
-                       newelemorder = DatumGetFloat4(Float4GetDatum(newelemorder));
+                       volatile float4 midpoint;
 
-                       if (newelemorder == nbr_en->enumsortorder ||
-                               newelemorder == other_nbr_en->enumsortorder)
+                       other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]);
+                       midpoint = (nbr_en->enumsortorder +
+                                               other_nbr_en->enumsortorder) / 2;
+
+                       if (midpoint == nbr_en->enumsortorder ||
+                               midpoint == other_nbr_en->enumsortorder)
                        {
                                RenumberEnumType(pg_enum, existing, nelems);
                                /* Clean up and start over */
@@ -337,6 +337,8 @@ restart:
                                ReleaseCatCacheList(list);
                                goto restart;
                        }
+
+                       newelemorder = midpoint;
                }
        }