* Copyright (c) 1998-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.90 2006/01/25 18:15:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.91 2006/02/07 16:03:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#define init_var(v) MemSetAligned(v, 0, sizeof(NumericVar))
+#define NUMERIC_DIGITS(num) ((NumericDigit *)(num)->n_data)
+#define NUMERIC_NDIGITS(num) \
+ (((num)->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit))
+
static void alloc_var(NumericVar *var, int ndigits);
static void free_var(NumericVar *var);
static void zero_var(NumericVar *var);
static int cmp_numerics(Numeric num1, Numeric num2);
static int cmp_var(NumericVar *var1, NumericVar *var2);
+static int cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
+ int var1weight, int var1sign,
+ const NumericDigit *var2digits, int var2ndigits,
+ int var2weight, int var2sign);
static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result,
int rscale);
static int cmp_abs(NumericVar *var1, NumericVar *var2);
+static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits,
+ int var1weight,
+ const NumericDigit *var2digits, int var2ndigits,
+ int var2weight);
static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);
static void round_var(NumericVar *var, int rscale);
}
else
{
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2);
-
- free_var(&arg1);
- free_var(&arg2);
+ result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
+ num1->n_weight, NUMERIC_SIGN(num1),
+ NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
+ num2->n_weight, NUMERIC_SIGN(num2));
}
return result;
static void
dump_numeric(const char *str, Numeric num)
{
- NumericDigit *digits = (NumericDigit *) num->n_data;
+ NumericDigit *digits = NUMERIC_DIGITS(num);
int ndigits;
int i;
- ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);
+ ndigits = NUMERIC_NDIGITS(num);
printf("%s: NUMERIC w=%d d=%d ", str, num->n_weight, NUMERIC_DSCALE(num));
switch (NUMERIC_SIGN(num))
{
int ndigits;
- ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);
+ ndigits = NUMERIC_NDIGITS(num);
alloc_var(dest, ndigits);
static int
cmp_var(NumericVar *var1, NumericVar *var2)
{
- if (var1->ndigits == 0)
+ return cmp_var_common(var1->digits, var1->ndigits,
+ var1->weight, var1->sign,
+ var2->digits, var2->ndigits,
+ var2->weight, var2->sign);
+}
+
+/*
+ * cmp_var_common() -
+ *
+ * Main routine of cmp_var(). This function can be used by both
+ * NumericVar and Numeric.
+ */
+static int
+cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
+ int var1weight, int var1sign,
+ const NumericDigit *var2digits, int var2ndigits,
+ int var2weight, int var2sign)
+{
+ if (var1ndigits == 0)
{
- if (var2->ndigits == 0)
+ if (var2ndigits == 0)
return 0;
- if (var2->sign == NUMERIC_NEG)
+ if (var2sign == NUMERIC_NEG)
return 1;
return -1;
}
- if (var2->ndigits == 0)
+ if (var2ndigits == 0)
{
- if (var1->sign == NUMERIC_POS)
+ if (var1sign == NUMERIC_POS)
return 1;
return -1;
}
- if (var1->sign == NUMERIC_POS)
+ if (var1sign == NUMERIC_POS)
{
- if (var2->sign == NUMERIC_NEG)
+ if (var2sign == NUMERIC_NEG)
return 1;
- return cmp_abs(var1, var2);
+ return cmp_abs_common(var1digits, var1ndigits, var1weight,
+ var2digits, var2ndigits, var2weight);
}
- if (var2->sign == NUMERIC_POS)
+ if (var2sign == NUMERIC_POS)
return -1;
- return cmp_abs(var2, var1);
+ return cmp_abs_common(var2digits, var2ndigits, var2weight,
+ var1digits, var1ndigits, var1weight);
}
static int
cmp_abs(NumericVar *var1, NumericVar *var2)
{
- NumericDigit *var1digits = var1->digits;
- NumericDigit *var2digits = var2->digits;
+ return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
+ var2->digits, var2->ndigits, var2->weight);
+}
+
+/* ----------
+ * cmp_abs_common() -
+ *
+ * Main routine of cmp_abs(). This function can be used by both
+ * NumericVar and Numeric.
+ * ----------
+ */
+static int
+cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight,
+ const NumericDigit *var2digits, int var2ndigits, int var2weight)
+{
int i1 = 0;
int i2 = 0;
- int w1 = var1->weight;
- int w2 = var2->weight;
/* Check any digits before the first common digit */
- while (w1 > w2 && i1 < var1->ndigits)
+ while (var1weight > var2weight && i1 < var1ndigits)
{
if (var1digits[i1++] != 0)
return 1;
- w1--;
+ var1weight--;
}
- while (w2 > w1 && i2 < var2->ndigits)
+ while (var2weight > var1weight && i2 < var2ndigits)
{
if (var2digits[i2++] != 0)
return -1;
- w2--;
+ var2weight--;
}
/* At this point, either w1 == w2 or we've run out of digits */
- if (w1 == w2)
+ if (var1weight == var2weight)
{
- while (i1 < var1->ndigits && i2 < var2->ndigits)
+ while (i1 < var1ndigits && i2 < var2ndigits)
{
int stat = var1digits[i1++] - var2digits[i2++];
* At this point, we've run out of digits on one side or the other; so any
* remaining nonzero digits imply that side is larger
*/
- while (i1 < var1->ndigits)
+ while (i1 < var1ndigits)
{
if (var1digits[i1++] != 0)
return 1;
}
- while (i2 < var2->ndigits)
+ while (i2 < var2ndigits)
{
if (var2digits[i2++] != 0)
return -1;