Clean up some problems with redundant cross-type arithmetic operators. Add
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Jun 2008 19:10:56 +0000 (19:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Jun 2008 19:10:56 +0000 (19:10 +0000)
int2-and-int8 implementations of the basic arithmetic operators +, -, *, /.
This doesn't really add any new functionality, but it avoids "operator is not
unique" failures that formerly occurred in these cases because the parser
couldn't decide whether to promote the int2 to int4 or int8.  We could
alternatively have removed the existing cross-type operators, but
experimentation shows that the cost of an additional type coercion expression
node is noticeable compared to such cheap operators; so let's not give up any
performance here.  On the other hand, I removed the int2-and-int4 modulo (%)
operators since they didn't seem as important from a performance standpoint.
Per a complaint last January from ykhuang.

src/backend/utils/adt/int.c
src/backend/utils/adt/int8.c
src/include/catalog/catversion.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/int8.h

index c77e214d765aba60f53de95d8a71c0f13c625888..b8d78b783d00a19137e4c0deb20ee7edea5577de 100644 (file)
@@ -1085,36 +1085,6 @@ int2mod(PG_FUNCTION_ARGS)
        PG_RETURN_INT16(arg1 % arg2);
 }
 
-Datum
-int24mod(PG_FUNCTION_ARGS)
-{
-       int16           arg1 = PG_GETARG_INT16(0);
-       int32           arg2 = PG_GETARG_INT32(1);
-
-       if (arg2 == 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_DIVISION_BY_ZERO),
-                                errmsg("division by zero")));
-       /* No overflow is possible */
-
-       PG_RETURN_INT32(arg1 % arg2);
-}
-
-Datum
-int42mod(PG_FUNCTION_ARGS)
-{
-       int32           arg1 = PG_GETARG_INT32(0);
-       int16           arg2 = PG_GETARG_INT16(1);
-
-       if (arg2 == 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_DIVISION_BY_ZERO),
-                                errmsg("division by zero")));
-       /* No overflow is possible */
-
-       PG_RETURN_INT32(arg1 % arg2);
-}
-
 
 /* int[24]abs()
  * Absolute value
index b831c63a8e90c888b09e93ccc7dfa8abeaba56aa..fa04a29b63d67ac224de413db6d6ba26163d2f3f 100644 (file)
@@ -922,6 +922,184 @@ int48div(PG_FUNCTION_ARGS)
        PG_RETURN_INT64((int64) arg1 / arg2);
 }
 
+Datum
+int82pl(PG_FUNCTION_ARGS)
+{
+       int64           arg1 = PG_GETARG_INT64(0);
+       int16           arg2 = PG_GETARG_INT16(1);
+       int64           result;
+
+       result = arg1 + arg2;
+
+       /*
+        * Overflow check.      If the inputs are of different signs then their sum
+        * cannot overflow.  If the inputs are of the same sign, their sum had
+        * better be that sign too.
+        */
+       if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int82mi(PG_FUNCTION_ARGS)
+{
+       int64           arg1 = PG_GETARG_INT64(0);
+       int16           arg2 = PG_GETARG_INT16(1);
+       int64           result;
+
+       result = arg1 - arg2;
+
+       /*
+        * Overflow check.      If the inputs are of the same sign then their
+        * difference cannot overflow.  If they are of different signs then the
+        * result should be of the same sign as the first input.
+        */
+       if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int82mul(PG_FUNCTION_ARGS)
+{
+       int64           arg1 = PG_GETARG_INT64(0);
+       int16           arg2 = PG_GETARG_INT16(1);
+       int64           result;
+
+       result = arg1 * arg2;
+
+       /*
+        * Overflow check.      We basically check to see if result / arg1 gives arg2
+        * again.  There is one case where this fails: arg1 = 0 (which cannot
+        * overflow).
+        *
+        * Since the division is likely much more expensive than the actual
+        * multiplication, we'd like to skip it where possible.  The best bang for
+        * the buck seems to be to check whether both inputs are in the int32
+        * range; if so, no overflow is possible.
+        */
+       if (arg1 != (int64) ((int32) arg1) &&
+               result / arg1 != arg2)
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int82div(PG_FUNCTION_ARGS)
+{
+       int64           arg1 = PG_GETARG_INT64(0);
+       int16           arg2 = PG_GETARG_INT16(1);
+       int64           result;
+
+       if (arg2 == 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DIVISION_BY_ZERO),
+                                errmsg("division by zero")));
+
+       result = arg1 / arg2;
+
+       /*
+        * Overflow check.      The only possible overflow case is for arg1 =
+        * INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN, which
+        * can't be represented on a two's-complement machine.
+        */
+       if (arg2 == -1 && arg1 < 0 && result < 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int28pl(PG_FUNCTION_ARGS)
+{
+       int16           arg1 = PG_GETARG_INT16(0);
+       int64           arg2 = PG_GETARG_INT64(1);
+       int64           result;
+
+       result = arg1 + arg2;
+
+       /*
+        * Overflow check.      If the inputs are of different signs then their sum
+        * cannot overflow.  If the inputs are of the same sign, their sum had
+        * better be that sign too.
+        */
+       if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int28mi(PG_FUNCTION_ARGS)
+{
+       int16           arg1 = PG_GETARG_INT16(0);
+       int64           arg2 = PG_GETARG_INT64(1);
+       int64           result;
+
+       result = arg1 - arg2;
+
+       /*
+        * Overflow check.      If the inputs are of the same sign then their
+        * difference cannot overflow.  If they are of different signs then the
+        * result should be of the same sign as the first input.
+        */
+       if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int28mul(PG_FUNCTION_ARGS)
+{
+       int16           arg1 = PG_GETARG_INT16(0);
+       int64           arg2 = PG_GETARG_INT64(1);
+       int64           result;
+
+       result = arg1 * arg2;
+
+       /*
+        * Overflow check.      We basically check to see if result / arg2 gives arg1
+        * again.  There is one case where this fails: arg2 = 0 (which cannot
+        * overflow).
+        *
+        * Since the division is likely much more expensive than the actual
+        * multiplication, we'd like to skip it where possible.  The best bang for
+        * the buck seems to be to check whether both inputs are in the int32
+        * range; if so, no overflow is possible.
+        */
+       if (arg2 != (int64) ((int32) arg2) &&
+               result / arg2 != arg1)
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("bigint out of range")));
+       PG_RETURN_INT64(result);
+}
+
+Datum
+int28div(PG_FUNCTION_ARGS)
+{
+       int16           arg1 = PG_GETARG_INT16(0);
+       int64           arg2 = PG_GETARG_INT64(1);
+
+       if (arg2 == 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DIVISION_BY_ZERO),
+                                errmsg("division by zero")));
+       /* No overflow is possible */
+       PG_RETURN_INT64((int64) arg1 / arg2);
+}
+
 /* Binary arithmetics
  *
  *             int8and         - returns arg1 & arg2
index ff4ce32ea5d38fcaf2626d4a88d49a39a2d82158..673f050009483b54cae91a781d09900ba5278adb 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200805261
+#define CATALOG_VERSION_NO     200806171
 
 #endif
index 0af47ac210186cd3e4eaab83a5621f1cb7693894..5f28c5a7f87bb0601afb6c9b9951370e67c2feab 100644 (file)
@@ -204,8 +204,6 @@ DATA(insert OID = 544 (  "*"           PGNSP PGUID b f f    21      23      23 545   0 int24mul - - )
 DATA(insert OID = 545 (  "*"      PGNSP PGUID b f f    23      21      23 544   0 int42mul - - ));
 DATA(insert OID = 546 (  "/"      PGNSP PGUID b f f    21      23      23       0       0 int24div - - ));
 DATA(insert OID = 547 (  "/"      PGNSP PGUID b f f    23      21      23       0       0 int42div - - ));
-DATA(insert OID = 548 (  "%"      PGNSP PGUID b f f    21      23      23       0       0 int24mod - - ));
-DATA(insert OID = 549 (  "%"      PGNSP PGUID b f f    23      21      23       0       0 int42mod - - ));
 DATA(insert OID = 550 (  "+"      PGNSP PGUID b f f    21      21      21 550   0 int2pl - - ));
 DATA(insert OID = 551 (  "+"      PGNSP PGUID b f f    23      23      23 551   0 int4pl - - ));
 DATA(insert OID = 552 (  "+"      PGNSP PGUID b f f    21      23      23 553   0 int24pl - - ));
@@ -321,6 +319,7 @@ DATA(insert OID = 684 (  "+"           PGNSP PGUID b f f    20      20      20 684   0 int8pl - - ));
 DATA(insert OID = 685 (  "-"      PGNSP PGUID b f f    20      20      20       0       0 int8mi - - ));
 DATA(insert OID = 686 (  "*"      PGNSP PGUID b f f    20      20      20 686   0 int8mul - - ));
 DATA(insert OID = 687 (  "/"      PGNSP PGUID b f f    20      20      20       0       0 int8div - - ));
+
 DATA(insert OID = 688 (  "+"      PGNSP PGUID b f f    20      23      20 692   0 int84pl - - ));
 DATA(insert OID = 689 (  "-"      PGNSP PGUID b f f    20      23      20       0       0 int84mi - - ));
 DATA(insert OID = 690 (  "*"      PGNSP PGUID b f f    20      23      20 694   0 int84mul - - ));
@@ -330,6 +329,15 @@ DATA(insert OID = 693 (  "-"          PGNSP PGUID b f f    23      20      20       0       0 int48mi - - ));
 DATA(insert OID = 694 (  "*"      PGNSP PGUID b f f    23      20      20 690   0 int48mul - - ));
 DATA(insert OID = 695 (  "/"      PGNSP PGUID b f f    23      20      20       0       0 int48div - - ));
 
+DATA(insert OID = 818 (  "+"      PGNSP PGUID b f f    20      21      20 822   0 int82pl - - ));
+DATA(insert OID = 819 (  "-"      PGNSP PGUID b f f    20      21      20       0       0 int82mi - - ));
+DATA(insert OID = 820 (  "*"      PGNSP PGUID b f f    20      21      20 824   0 int82mul - - ));
+DATA(insert OID = 821 (  "/"      PGNSP PGUID b f f    20      21      20       0       0 int82div - - ));
+DATA(insert OID = 822 (  "+"      PGNSP PGUID b f f    21      20      20 818   0 int28pl - - ));
+DATA(insert OID = 823 (  "-"      PGNSP PGUID b f f    21      20      20       0       0 int28mi - - ));
+DATA(insert OID = 824 (  "*"      PGNSP PGUID b f f    21      20      20 820   0 int28mul - - ));
+DATA(insert OID = 825 (  "/"      PGNSP PGUID b f f    21      20      20       0       0 int28div - - ));
+
 DATA(insert OID = 706 (  "<->"    PGNSP PGUID b f f 603 603 701 706     0 box_distance - - ));
 DATA(insert OID = 707 (  "<->"    PGNSP PGUID b f f 602 602 701 707     0 path_distance - - ));
 DATA(insert OID = 708 (  "<->"    PGNSP PGUID b f f 628 628 701 708     0 line_distance - - ));
index 99f42d326324e9c7b86bb2383c0694a3f75b62f6..42e382724ebba4af75ca8d792fe50be0c533c98f 100644 (file)
@@ -351,10 +351,6 @@ DATA(insert OID = 172 (  int24div             PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23"
 DESCR("divide");
 DATA(insert OID = 173 (  int42div                 PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42div - _null_ _null_ ));
 DESCR("divide");
-DATA(insert OID = 174 (  int24mod                 PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23" _null_ _null_ _null_ int24mod - _null_ _null_ ));
-DESCR("modulus");
-DATA(insert OID = 175 (  int42mod                 PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42mod - _null_ _null_ ));
-DESCR("modulus");
 DATA(insert OID = 176 (  int2pl                           PGNSP PGUID 12 1 0 f f t f i 2 21 "21 21" _null_ _null_ _null_ int2pl - _null_ _null_ ));
 DESCR("add");
 DATA(insert OID = 177 (  int4pl                           PGNSP PGUID 12 1 0 f f t f i 2 23 "23 23" _null_ _null_ _null_ int4pl - _null_ _null_ ));
@@ -1177,10 +1173,6 @@ DATA(insert OID = 940 (  mod                        PGNSP PGUID 12 1 0 f f t f i 2 21 "21 21" _nul
 DESCR("modulus");
 DATA(insert OID = 941 (  mod                      PGNSP PGUID 12 1 0 f f t f i 2 23 "23 23" _null_ _null_ _null_ int4mod - _null_ _null_ ));
 DESCR("modulus");
-DATA(insert OID = 942 (  mod                      PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23" _null_ _null_ _null_ int24mod - _null_ _null_ ));
-DESCR("modulus");
-DATA(insert OID = 943 (  mod                      PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42mod - _null_ _null_ ));
-DESCR("modulus");
 
 DATA(insert OID = 945 (  int8mod                  PGNSP PGUID 12 1 0 f f t f i 2 20 "20 20" _null_ _null_ _null_ int8mod - _null_ _null_ ));
 DESCR("modulus");
@@ -1570,6 +1562,23 @@ DESCR("multiply");
 DATA(insert OID = 1281 (  int48div                PGNSP PGUID 12 1 0 f f t f i 2 20 "23 20" _null_ _null_ _null_ int48div - _null_ _null_ ));
 DESCR("divide");
 
+DATA(insert OID =  837 (  int82pl                 PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82pl - _null_ _null_ ));
+DESCR("add");
+DATA(insert OID =  838 (  int82mi                 PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82mi - _null_ _null_ ));
+DESCR("subtract");
+DATA(insert OID =  839 (  int82mul                PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82mul - _null_ _null_ ));
+DESCR("multiply");
+DATA(insert OID =  840 (  int82div                PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82div - _null_ _null_ ));
+DESCR("divide");
+DATA(insert OID =  841 (  int28pl                 PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28pl - _null_ _null_ ));
+DESCR("add");
+DATA(insert OID =  942 (  int28mi                 PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28mi - _null_ _null_ ));
+DESCR("subtract");
+DATA(insert OID =  943 (  int28mul                PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28mul - _null_ _null_ ));
+DESCR("multiply");
+DATA(insert OID =  948 (  int28div                PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28div - _null_ _null_ ));
+DESCR("divide");
+
 DATA(insert OID = 1287 (  oid                     PGNSP PGUID 12 1 0 f f t f i 1 26 "20" _null_ _null_ _null_  i8tooid - _null_ _null_ ));
 DESCR("convert int8 to oid");
 DATA(insert OID = 1288 (  int8                    PGNSP PGUID 12 1 0 f f t f i 1 20 "26" _null_ _null_ _null_  oidtoi8 - _null_ _null_ ));
index 91869d9b2a2635e32ed1f33f6011edc99dc51de3..a3fa7ec1b6107101deae9a8fc23f57926c7b3645 100644 (file)
@@ -190,8 +190,6 @@ extern Datum int42mul(PG_FUNCTION_ARGS);
 extern Datum int42div(PG_FUNCTION_ARGS);
 extern Datum int4mod(PG_FUNCTION_ARGS);
 extern Datum int2mod(PG_FUNCTION_ARGS);
-extern Datum int24mod(PG_FUNCTION_ARGS);
-extern Datum int42mod(PG_FUNCTION_ARGS);
 extern Datum int2larger(PG_FUNCTION_ARGS);
 extern Datum int2smaller(PG_FUNCTION_ARGS);
 extern Datum int4larger(PG_FUNCTION_ARGS);
index f753b399e3d898dfab9a7877f8f5f6fe7c36bd26..e84a8c788b056c42241411a7824a0237c5bb1744 100644 (file)
@@ -96,6 +96,16 @@ extern Datum int48mi(PG_FUNCTION_ARGS);
 extern Datum int48mul(PG_FUNCTION_ARGS);
 extern Datum int48div(PG_FUNCTION_ARGS);
 
+extern Datum int82pl(PG_FUNCTION_ARGS);
+extern Datum int82mi(PG_FUNCTION_ARGS);
+extern Datum int82mul(PG_FUNCTION_ARGS);
+extern Datum int82div(PG_FUNCTION_ARGS);
+
+extern Datum int28pl(PG_FUNCTION_ARGS);
+extern Datum int28mi(PG_FUNCTION_ARGS);
+extern Datum int28mul(PG_FUNCTION_ARGS);
+extern Datum int28div(PG_FUNCTION_ARGS);
+
 extern Datum int48(PG_FUNCTION_ARGS);
 extern Datum int84(PG_FUNCTION_ARGS);