On Sun, Jan 25, 2009 at 10:27:03PM -0600, Kenneth Marshall wrote:
> On Sat, Jan 10, 2009 at 01:36:25PM -0500, Tom Lane wrote:
> > Jeff Davis <pg...@j-davis.com> writes:
> > > I ran 5 times on both old and new code, eliminating the top and bottom
> > > and taking the average of the remaining 3, and I got a 6.9% performance
> > > improvement with the new code.
> > 
> > The question that has been carefully evaded throughout the discussion
> > of this patch is whether the randomness of the hash result is decreased,
> > and if so what is that likely to cost us in performance of the various
> > hash-dependent algorithms.  I would still like to have an answer to that
> > before we make a change to gain marginal performance improvement in
> > the hash function itself (which is already shown to be barely measurable
> > in the total context of a hash-dependent operation...)
> > 
> >                     regards, tom lane
> > 
> 
> Dear Hackers and Reviewers,
> 
> In response to Tom's questioning the randomness of the hash_any
> when the mixing functions are split into two, the first used when
> sequentially processing the input and the second for the final
> mix, I have generated a more detailed analysis of the two hash_any
> functions.
> 
> First, one change to the 11/2008 patch, the keylen is added to a, b and
> c initially so we do not need to add it later on. The is the
> micro-diff:
> -----------------------------
> 
> --- hashfunc.c_TWOMIX   2009-01-22 14:07:34.000000000 -0600
> +++ hashfunc.c_TWOMIX2  2009-01-22 14:17:32.000000000 -0600
> @@ -336,7 +336,6 @@
>  
>                 /* handle the last 11 bytes */
>                 k = (const unsigned char *) ka;
> -               c += keylen;
>  #ifdef WORDS_BIGENDIAN
>                 switch (len)
>                 {
> @@ -439,7 +438,6 @@
>                 }
>  
>                 /* handle the last 11 bytes */
> -               c += keylen;
>  #ifdef WORDS_BIGENDIAN
>                 switch (len)                    /* all the case statements 
> fall through */
>  
> -----------------------------
> 
> The remainder of this document will use the runs from my initial results
> broken out using various power-of-two bucket sizes to simulate our actual
> use in PostgreSQL as the number of items hashed increases and we use more
> and more bits of our hash to identify the appropriate bucket. I have run
> each test twice, once with our current hash_any() with the single mix()
> function and then a second time using my patch from the November commitfest
> plus the patch above to produce a new hash_any() with two separate mixing
> functions mix() and final(). For each run I have generated a sequence of
> unique inputs, up to the number of buckets, hashed them with the hash
> functions (both old and new), then I calculate the expected number of
> collision p(n) using the poisson formula for each number of buckets,
> where the number of buckets are 2**16, 2**18, 2**20, 2**22, 2**24, and
> 2**26. For my initial run, I used a string consisting of the letter 'a'
> followed by the integer representation of the numbers from 0 to the
> (number of buckets - 1):
> 
> 1) "a"uint32 ((i.e. a00001,a0002...)
> Number of buckets: 65536
> Total number of items: 65536
> Expected number with n items: 24109 24109 12054 4018 1004 200 33 4
> Actual number mix():          24044 24172 12078 4036 980 186 30 10
> Actual number mix()/final():  24027 24232 12060 3972 1001 207 31 5 1
> 
> Number of buckets: 262144
> Total number of items: 262144
> Expected number with n items: 96437 96437 48218 16072 4018 803 133 19 2
> Actual number mix():          96224 96730 48240 15951 4094 744 143 17 1
> Actual number mix()/final():  96335 96646 48071 16128 4018 801 122 21 2
> 
> Number of buckets: 1048576
> Total number of items: 1048576
> Expected number with n items: 385749 385749 192874 64291 16072 3214 535 76 9
> Actual number mix():          385716 385596 193243 64115 16053 3285 478 77 12 
> 1
> Actual number mix()/final():  385955 385016 193789 63768 16259 3190 511 79 8 1
> 
> Number of buckets: 4194304
> Total number of items: 4194304
> Expected number with n items: 1542998 1542998 771499 257166 64291 12858 2143 
> 306 38
> Actual number mix():          1542536 1543489 771351 257777 63830 12847 2123 
> 326 19 5 1
> Actual number mix()/final():  1541828 1544429 772072 256178 64579 12774 2129 
> 288 22 5
> 
> Number of buckets: 16777216
> Total number of items: 16777216
> Expected number with n items: 6171992 6171992 3085996 1028665 257166 51433 
> 8572 1224 153
> Actual number mix():          6170866 6174079 3085912 1027140 257808 51385 
> 8638 1219 146 23
> Actual number mix()/final():  6172058 6171991 3086279 1027916 257535 51465 
> 8554 1243 149 23 3
> 
> Number of buckets: 67108864
> Total number of items: 67108864
> Expected number with n items: 24687971 24687971 12343985 4114661 1028665 
> 205733 34288 4898 612
> Actual number mix():          24686110 24690897 12344232 4113515 1028232 
> 205682 34546 4942 629 72 7
> Actual number mix()/final():  24708515 24669248 12333034 4114796 1034256 
> 208424 34888 5023 598 77 5
> 
> Here is a second run with number of items = (number of buckets)/2:
> Number of buckets: 65536
> Total number of items: 32768
> Expected number with n items: 39749 19874 4968 828 103 10
> Actual number mix():          39704 19978 4898 842 103 10 1
> Actual number mix()/final():  39715 19922 4991 779 119 9 1
> 
> Number of buckets: 262144
> Total number of items: 131072
> Expected number with n items: 158998 79499 19874 3312 414 41 3
> Actual number mix():          158753 79972 19703 3216 458 38 4
> Actual number mix()/final():  158869 79688 19853 3303 393 33 3 2
> 
> Number of buckets: 1048576
> Total number of items: 524288
> Expected number with n items: 635993 317996 79499 13249 1656 165 13
> Actual number mix():          636118 317839 79388 13435 1628 152 16
> Actual number mix()/final():  636102 317824 79527 13267 1683 161 12
> 
> Number of buckets: 4194304
> Total number of items: 2097152
> Expected number with n items: 2543973 1271986 317996 52999 6624 662 55 3
> Actual number mix():          2544529 1270639 318904 53005 6516 645 61 5
> Actual number mix()/final():  2544014 1271483 318720 52849 6559 630 47 2
> 
> Number of buckets: 16777216
> Total number of items: 8388608
> Expected number with n items: 10175895 5087947 1271986 211997 26499 2649 220 
> 15
> Actual number mix():          10174997 5089736 1271355 211528 26679 2683 220 
> 17 1
> Actual number mix()/final():  10176567 5087207 1271789 212014 26684 2703 235 
> 16 1
> 
> Number of buckets: 67108864
> Total number of items: 33554432
> Expected number with n items: 40703583 20351791 5087947 847991 105998 10599 
> 883 63 3
> Actual number mix():          40703033 20353345 5086252 848860 105885 10536 
> 891 59 3
> Actual number mix()/final():  40770874 20250828 5096890 865448 111835 11890 
> 1013 76 10
> 
> 2) uint32uint32 (i.e. uint64)
> Number of buckets: 65536
> Total number of items: 32768
> Expected number with n items: 39749 19874 4968 828 103 10
> Actual number mix():          39770 19863 4947 822 125 9
> Actual number mix()/final():  39754 19852 4990 837 91 11 1
> 
> Number of buckets: 262144
> Total number of items: 131072
> Expected number with n items: 158998 79499 19874 3312 414 41 3
> Actual number mix():          159046 79464 19823 3334 430 43 3 1
> Actual number mix()/final():  158879 79732 19774 3301 406 47 5
> 
> Number of buckets: 1048576
> Total number of items: 524288
> Expected number with n items: 635993 317996 79499 13249 1656 165 13
> Actual number mix():          636275 317580 79514 13357 1661 172 14 3
> Actual number mix()/final():  635578 318574 79504 13162 1585 159 13 1
> 
> Number of buckets: 4194304
> Total number of items: 2097152
> Expected number with n items: 2543973 1271986 317996 52999 6624 662 55 3
> Actual number mix():          2543769 1272196 318067 53050 6497 672 48 4 1
> Actual number mix()/final():  2543014 1273485 317812 52703 6589 635 59 7
> 
> Number of buckets: 16777216
> Total number of items: 8388608
> Expected number with n items: 10175895 5087947 1271986 211997 26499 2649 220 
> 15
> Actual number mix():          10174587 5090467 1270909 211836 26513 2679 207 
> 18
> Actual number mix()/final():  10175142 5089481 1270919 212555 26234 2643 224 
> 15 3
> 
> Number of buckets: 67108864
> Total number of items: 33554432
> Expected number with n items: 40703583 20351791 5087947 847991 105998 10599 
> 883 63 3
> Actual number mix():          40706281 20347746 5088639 848133 106388 10669 
> 946 60 2
> Actual number mix()/final():  40701438 20354677 5088549 846570 106157 10578 
> 838 55 2
> 
> 3) uint32 from 1-1648379
> Number of buckets: 65536
> Total number of items: 32768
> Expected number with n items: 39749 19874 4968 828 103 10
> Actual number mix():          39758 19844 4993 835 97 9
> Actual number mix()/final():  39842 19712 5016 849 109 7 1
> 
> Number of buckets: 262144
> Total number of items: 131072
> Expected number with n items: 158998 79499 19874 3312 414 41 3
> Actual number mix():          158973 79523 19900 3283 426 38 1
> Actual number mix()/final():  159136 79293 19896 3346 421 48 3 1
> 
> Number of buckets: 1048576
> Total number of items: 524288
> Expected number with n items: 635993 317996 79499 13249 1656 165 13
> Actual number mix():          636083 317917 79484 13183 1711 180 16 2
> Actual number mix()/final():  636183 317772 79438 13305 1685 173 20
> 
> Number of buckets: 4194304
> Total number of items: 2097152
> Expected number with n items: 2543973 1271986 317996 52999 6624 662 55 3
> Actual number mix():          2544325 1271367 318260 52950 6660 683 54 4 1
> Actual number mix()/final():  2544022 1272059 317778 53060 6646 665 70 4
> 
> Number of buckets: 16777216
> Total number of items: 8388608
> Expected number with n items: 10175895 5087947 1271986 211997 26499 2649 220 
> 15
> Actual number mix():          10176360 5087249 1272083 212010 26655 2629 212 
> 18
> Actual number mix()/final():  10175315 5088617 1272068 212144 26224 2589 234 
> 23 1 1
> 
> Number of buckets: 67108864
> Total number of items: 33554432
> Expected number with n items: 40703583 20351791 5087947 847991 105998 10599 
> 883 63 3
> Actual number mix():          40704034 20350542 5088760 848309 105721 10520 
> 894 77 7
> Actual number mix()/final():  40774785 20243786 5098862 866801 111865 11641 
> 1019 100 5
> 
> 4) cracklib
> Number of buckets: 65536
> Total number of items: 32767
> Expected number with n items: 39750 19874 4968 828 103 10
> Actual number mix():          39731 19858 5049 794 92 11 1
> Actual number mix()/final():  39785 19801 5011 823 106 9 1
> 
> Number of buckets: 262144
> Total number of items: 131071
> Expected number with n items: 158998 79498 19874 3312 414 41 3
> Actual number mix():          159077 79420 19806 3380 409 49 3
> Actual number mix()/final():  159020 79475 19845 3366 383 54 1
> 
> Number of buckets: 1048576
> Total number of items: 524287
> Expected number with n items: 635994 317996 79498 13249 1656 165 13
> Actual number mix():          635979 318066 79420 13281 1641 163 23 3
> Actual number mix()/final():  635694 318637 79122 13271 1686 150 13 3
> 
> Number of buckets: 4194304
> Total number of items: 1648379
> Expected number with n items: 2831263 1112698 218647 28643 2814 221 14
> Actual number mix():          2830769 1113458 218633 28396 2786 250 11 1
> Actual number mix()/final():  2831304 1113004 218002 28843 2926 212 13
> 
> Number of buckets: 16777216
> Total number of items: 1648379
> Expected number with n items: 15207226 1494125 73399 2403 59 1
> Actual number mix():          15206923 1494718 73129 2384 59 3
> Actual number mix()/final():  15207183 1494267 73250 2452 64
> 
> Number of buckets: 67108864
> Total number of items: 1648379
> Expected number with n items: 65480564 1608383 19753 161 1.47989202515749e-08
> Actual number mix():          65480389 1608727 19593 154 1
> Actual number mix()/final():  65480455 1608609 19631 168 1
> 
> 5) cracklib x 100
> Number of buckets: 65536
> Total number of items: 32767
> Expected number with n items: 39750 19874 4968 828 103 10
> Actual number mix():          39829 19742 5003 847 99 14 2
> Actual number mix()/final():  39783 19794 5023 828 97 11
> 
> Number of buckets: 262144
> Total number of items: 131071
> Expected number with n items: 158998 79498 19874 3312 414 41 3
> Actual number mix():          159136 79242 20007 3289 405 62 3
> Actual number mix()/final():  158961 79546 19905 3270 408 51 3
> 
> Number of buckets: 1048576
> Total number of items: 524287
> Expected number with n items: 635994 317996 79498 13249 1656 165 13
> Actual number mix():          635815 318331 79372 13218 1658 168 12 2
> Actual number mix()/final():  635986 318152 79309 13231 1687 190 21
> 
> Number of buckets: 4194304
> Total number of items: 1648379
> Expected number with n items: 2831263 1112698 218647 28643 2814 221 14
> Actual number mix():          2830891 1113468 218202 28712 2804 208 18 1
> Actual number mix()/final():  2831786 1111616 219209 28661 2816 199 16 1
> 
> Number of buckets: 16777216
> Total number of items: 1648379
> Expected number with n items: 15207226 1494125 73399 2403 59 1
> Actual number mix():          15207428 1493777 73492 2459 59 1
> Actual number mix()/final():  15207777 1493063 73877 2435 63 1
> 
> Number of buckets: 67108864
> Total number of items: 1648379
> Expected number with n items: 65480564 1608383 19753 161 1.47989202515749e-08
> Actual number mix():          65480463 1608595 19635 170 1
> Actual number mix()/final():  65480650 1608222 19820 171 1
> 
> As you can see, all of the probabilities for both the current single mix()
> function and the split mix()/final() functions match the theoretical results
> as calculated by the poisson formula. Here is a nice reference that I found
> online describing the testing procedure that I am using:
> 
> http://rabbit.eng.miami.edu/class/een318/poisson.pdf
> 
> I can find no situations where the current version of hash_any() performs
> statistically better than the version resulting from my split mix()/final()
> function patch from 11/2008. I would be happy to share the test harness with
> anyone who wishes to test further. Please let me know if there is anything
> I can do. I still recommend applying the split mixing function patch that
> I submitted for the 11/2008 commitfest and I think these tests should allay
> Tom's concerns about the randomness of the new hash function.
> 
> Regards,
> Ken Marshall
> 
Dear Hackers,

I have updated the patch posted by Jeff Davis on January 9th
to include the micro-patch above as well as updated the polymorphism
regressions tests. This applies cleanly to the latest CVS pull.

Regards,
Ken

--- a/src/backend/access/hash/hashfunc.c        2009-01-27 09:57:18.000000000 
-0600
+++ b/src/backend/access/hash/hashfunc.c        2009-01-27 09:54:21.000000000 
-0600
@@ -200,39 +200,94 @@
  * hash function, see http://burtleburtle.net/bob/hash/doobs.html,
  * or Bob's article in Dr. Dobb's Journal, Sept. 1997.
  *
- * In the current code, we have adopted an idea from Bob's 2006 update
- * of his hash function, which is to fetch the data a word at a time when
- * it is suitably aligned.  This makes for a useful speedup, at the cost
- * of having to maintain four code paths (aligned vs unaligned, and
- * little-endian vs big-endian).  Note that we have NOT adopted his newer
- * mix() function, which is faster but may sacrifice some randomness.
+ * In the current code, we have adopted Bob's 2006 update of his hash
+ * which fetches the data a word at a time when it is suitably aligned.
+ * This makes for a useful speedup, at the cost of having to maintain
+ * four code paths (aligned vs unaligned, and little-endian vs big-endian).
+ * It also two separate mixing functions mix() and final(), instead
+ * of a slower multi-purpose function.
  */
 
 /* Get a bit mask of the bits set in non-uint32 aligned addresses */
 #define UINT32_ALIGN_MASK (sizeof(uint32) - 1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 
 /*----------
  * mix -- mix 3 32-bit values reversibly.
- * For every delta with one or two bits set, and the deltas of all three
- * high bits or all three low bits, whether the original value of a,b,c
- * is almost all zero or is uniformly distributed,
- * - If mix() is run forward or backward, at least 32 bits in a,b,c
- *      have at least 1/4 probability of changing.
- * - If mix() is run forward, every bit of c will change between 1/3 and
- *      2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
+ *
+ * This is reversible, so any information in (a,b,c) before mix() is
+ * still in (a,b,c) after mix().
+ *
+ * If four pairs of (a,b,c) inputs are run through mix(), or through
+ * mix() in reverse, there are at least 32 bits of the output that
+ * are sometimes the same for one pair and different for another pair.
+ * This was tested for:
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ *   all zero plus a counter that starts at zero.
+ * 
+ * This does not achieve avalanche.  There are input bits of (a,b,c)
+ * that fail to affect some output bits of (a,b,c), especially of a.  The
+ * most thoroughly mixed value is c, but it doesn't really even achieve
+ * avalanche in c. 
+ * 
+ * This allows some parallelism.  Read-after-writes are good at doubling
+ * the number of bits affected, so the goal of mixing pulls in the opposite
+ * direction as the goal of parallelism.  I did what I could.  Rotates
+ * seem to cost as much as shifts on every machine I could lay my hands
+ * on, and rotates are much kinder to the top and bottom bits, so I used
+ * rotates.
  *----------
  */
 #define mix(a,b,c) \
 { \
-  a -= b; a -= c; a ^= ((c)>>13); \
-  b -= c; b -= a; b ^= ((a)<<8); \
-  c -= a; c -= b; c ^= ((b)>>13); \
-  a -= b; a -= c; a ^= ((c)>>12);  \
-  b -= c; b -= a; b ^= ((a)<<16); \
-  c -= a; c -= b; c ^= ((b)>>5); \
-  a -= b; a -= c; a ^= ((c)>>3);       \
-  b -= c; b -= a; b ^= ((a)<<10); \
-  c -= a; c -= b; c ^= ((b)>>15); \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*----------
+ * final -- final mixing of 3 32-bit values (a,b,c) into c
+ *
+ * Pairs of (a,b,c) values differing in only a few bits will usually
+ * produce values of c that look totally different.  This was tested for
+ * * pairs that differed by one bit, by two bits, in any combination
+ *   of top bits of (a,b,c), or in any combination of bottom bits of
+ *   (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+ *   the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ *   is commonly produced by subtraction) look like a single 1-bit
+ *   difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ *   all zero plus a counter that starts at zero.
+ *     
+ * The use of separate functions for mix() and final() allow for a
+ * substantial performance increase since final() does not need to
+ * do well in reverse, but is does need to affect all output bits.
+ * mix(), on the other hand, does not need to affect all output
+ * bits (affecting 32 bits is enough).The original hash function had
+ * a single mixing operation that had to satisfy both sets of requirements
+ * and was slower as a result.
+ *----------
+ */
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
 }
 
 /*
@@ -260,8 +315,7 @@
 
        /* Set up the internal state */
        len = keylen;
-       a = b = 0x9e3779b9;                     /* the golden ratio; an 
arbitrary value */
-       c = 3923095;                            /* initialize with an arbitrary 
value */
+       a = b = c = 0x9e3779b9 + len + 3923095;
 
        /* If the source pointer is word-aligned, we use word-wide fetches */
        if (((long) k & UINT32_ALIGN_MASK) == 0)
@@ -282,7 +336,6 @@
 
                /* handle the last 11 bytes */
                k = (const unsigned char *) ka;
-               c += keylen;
 #ifdef WORDS_BIGENDIAN
                switch (len)
                {
@@ -385,7 +438,6 @@
                }
 
                /* handle the last 11 bytes */
-               c += keylen;
 #ifdef WORDS_BIGENDIAN
                switch (len)                    /* all the case statements fall 
through */
                {
@@ -445,7 +497,7 @@
 #endif /* WORDS_BIGENDIAN */
        }
 
-       mix(a, b, c);
+       final(a, b, c);
 
        /* report the result */
        return UInt32GetDatum(c);
@@ -465,11 +517,10 @@
                                b,
                                c;
 
-       a = 0x9e3779b9 + k;
-       b = 0x9e3779b9;
-       c = 3923095 + (uint32) sizeof(uint32);
+       a = b = c = 0x9e3779b9 + (uint32) sizeof(uint32) + 3923095;
+       a += k;
 
-       mix(a, b, c);
+       final(a, b, c);
 
        /* report the result */
        return UInt32GetDatum(c);
--- a/src/test/regress/expected/polymorphism.out        2009-01-27 
09:52:15.000000000 -0600
+++ b/src/test/regress/expected/polymorphism.out        2009-01-27 
10:12:07.000000000 -0600
@@ -355,184 +355,184 @@
 select f3, myaggp01a(*) from t group by f3;
  f3 | myaggp01a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp03a(*) from t group by f3;
  f3 | myaggp03a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp03b(*) from t group by f3;
  f3 | myaggp03b 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp05a(f1) from t group by f3;
  f3 | myaggp05a 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggp06a(f1) from t group by f3;
  f3 | myaggp06a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp08a(f1) from t group by f3;
  f3 | myaggp08a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp09a(f1) from t group by f3;
  f3 | myaggp09a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp09b(f1) from t group by f3;
  f3 | myaggp09b 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggp10a(f1) from t group by f3;
  f3 | myaggp10a 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggp10b(f1) from t group by f3;
  f3 | myaggp10b 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggp20a(f1) from t group by f3;
  f3 | myaggp20a 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggp20b(f1) from t group by f3;
  f3 | myaggp20b 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggn01a(*) from t group by f3;
  f3 | myaggn01a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn01b(*) from t group by f3;
  f3 | myaggn01b 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn03a(*) from t group by f3;
  f3 | myaggn03a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn05a(f1) from t group by f3;
  f3 | myaggn05a 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggn05b(f1) from t group by f3;
  f3 | myaggn05b 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
 select f3, myaggn06a(f1) from t group by f3;
  f3 | myaggn06a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn06b(f1) from t group by f3;
  f3 | myaggn06b 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn08a(f1) from t group by f3;
  f3 | myaggn08a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn08b(f1) from t group by f3;
  f3 | myaggn08b 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn09a(f1) from t group by f3;
  f3 | myaggn09a 
 ----+-----------
- b  | {}
  c  | {}
+ b  | {}
  a  | {}
 (3 rows)
 
 select f3, myaggn10a(f1) from t group by f3;
  f3 | myaggn10a 
 ----+-----------
- b  | {1,2,3}
  c  | {1,2}
+ b  | {1,2,3}
  a  | {1,2,3}
 (3 rows)
 
--- a/src/test/regress/expected/union.out       2009-01-27 09:56:52.000000000 
-0600
+++ b/src/test/regress/expected/union.out       2009-01-27 09:55:31.000000000 
-0600
@@ -263,16 +263,16 @@
 SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl;
         q2        
 ------------------
-              123
  4567890123456789
+              123
 (2 rows)
 
 SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl;
         q2        
 ------------------
-              123
  4567890123456789
  4567890123456789
+              123
 (3 rows)
 
 SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1;
@@ -305,16 +305,16 @@
 SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl;
         q1        
 ------------------
-              123
  4567890123456789
+              123
 (2 rows)
 
 SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl;
         q1        
 ------------------
-              123
  4567890123456789
  4567890123456789
+              123
 (3 rows)
 
 --
@@ -341,8 +341,8 @@
 SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 
FROM int8_tbl;
         q1         
 -------------------
-               123
   4567890123456789
+               123
                456
   4567890123456789
                123
@@ -353,15 +353,15 @@
 SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT 
q2 FROM int8_tbl)));
         q1        
 ------------------
-              123
  4567890123456789
+              123
 (2 rows)
 
 (((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl))) UNION ALL 
SELECT q2 FROM int8_tbl;
         q1         
 -------------------
-               123
   4567890123456789
+               123
                456
   4567890123456789
                123
@@ -416,8 +416,8 @@
 SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 
1)));
         q1        
 ------------------
-              123
  4567890123456789
+              123
 (2 rows)
 
 --
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to