Index: ChangeLog
===================================================================
--- ChangeLog	(revision 16471)
+++ ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2008-03-20  Morten Welinder  <terra@gnome.org>
+
+	* src/value.c (criteria_test_equal, criteria_test_unequal,
+	criteria_test_less, criteria_test_less_or_equal,
+	criteria_test_greater, criteria_test_greater_or_equal): Handle
+	string values that can be interpreted as numbers.  Take extra
+	date_conv argument.  All callers changed.
+
 2008-03-12  Morten Welinder  <terra@gnome.org>
 
 	* src/xml-sax-read.c (make_format): New function to handle invalid
Index: NEWS
===================================================================
--- NEWS	(revision 16471)
+++ NEWS	(working copy)
@@ -56,6 +56,7 @@
 	* Don't allocate memory for boolean values.  [#518527]
 	* Ignore invalid formats read from .gnumeric and .xls.  [#521849]
 	* Don't allow entry of invalid formats for cells.  [#521849]
+	* Fix SUMIF problems.  [#523250]
 
 Nick Lamb:
 	* Honour detachable-toolbar preference.  [#321867]
Index: src/value.c
===================================================================
--- src/value.c	(revision 16471)
+++ src/value.c	(working copy)
@@ -1335,77 +1335,149 @@
 
 /****************************************************************************/
 
+typedef enum { CRIT_NULL, CRIT_FLOAT, CRIT_BADFLOAT, CRIT_STRING } CritType;
+
+static CritType
+criteria_inspect_values (GnmValue const *x, GnmValue const *y,
+			 gnm_float *xr, gnm_float *yr,
+			 GODateConventions const *date_conv)
+{
+	GnmValue *vx;
+
+	if (x == NULL || y == NULL)
+		return CRIT_NULL;
+
+	if (!VALUE_IS_NUMBER (y))
+		return CRIT_STRING;
+	*yr = value_get_as_float (y);
+
+	if (VALUE_IS_NUMBER (x)) {
+		*xr = value_get_as_float (x);
+		return CRIT_FLOAT;
+	}
+
+	vx = format_match (value_peek_string (x), NULL, date_conv);
+	if (!vx)
+		return CRIT_BADFLOAT;
+
+	*xr = value_get_as_float (vx);
+	value_release (vx);
+	return CRIT_FLOAT;
+}
+
+
 static gboolean
-criteria_test_equal (GnmValue const *x, GnmValue const *y)
+criteria_test_equal (GnmValue const *x, GnmValue const *y,
+		     GODateConventions const *date_conv)
 {
-	if (x == NULL || y == NULL)
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
 		return FALSE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) == value_get_as_float (y));
-	else
-		return (VALUE_IS_STRING (x) &&
-			VALUE_IS_STRING (y) &&
-			g_ascii_strcasecmp (x->v_str.val->str, y->v_str.val->str) == 0);
+	case CRIT_FLOAT:
+		return xf == yf;
+	case CRIT_STRING:
+		/* FIXME: _ascii_??? */
+		return g_ascii_strcasecmp (value_peek_string (x),
+					   value_peek_string (y)) == 0;
+	}
 }
 
 static gboolean
-criteria_test_unequal (GnmValue const *x, GnmValue const *y)
+criteria_test_unequal (GnmValue const *x, GnmValue const *y,
+		       GODateConventions const *date_conv)
 {
-	if (x == NULL)
-		return y != NULL;
-	if (y == NULL)
-		return TRUE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) != value_get_as_float (y));
-	else
-		/* Hmm...  Is this really right?  number vs string, not unequal?  */
-		return (VALUE_IS_STRING (x) &&
-			VALUE_IS_STRING (y) &&
-			g_ascii_strcasecmp (x->v_str.val->str, y->v_str.val->str) != 0);
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
+		return FALSE;
+	case CRIT_FLOAT:
+		return xf != yf;
+	case CRIT_STRING:
+		/* FIXME: _ascii_??? */
+		return g_ascii_strcasecmp (value_peek_string (x),
+					   value_peek_string (y)) != 0;
+	}
 }
 
 static gboolean
-criteria_test_less (GnmValue const *x, GnmValue const *y)
+criteria_test_less (GnmValue const *x, GnmValue const *y,
+		    GODateConventions const *date_conv)
 {
-	if (x == NULL || y == NULL)
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
+	case CRIT_STRING:
 		return FALSE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) < value_get_as_float (y));
-	else
-		return FALSE;
+	case CRIT_FLOAT:
+		return xf < yf;
+	}
 }
 
 static gboolean
-criteria_test_greater (GnmValue const *x, GnmValue const *y)
+criteria_test_greater (GnmValue const *x, GnmValue const *y,
+		       GODateConventions const *date_conv)
 {
-	if (x == NULL || y == NULL)
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
+	case CRIT_STRING:
 		return FALSE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) > value_get_as_float (y));
-	else
-		return FALSE;
+	case CRIT_FLOAT:
+		return xf > yf;
+	}
 }
 
 static gboolean
-criteria_test_less_or_equal (GnmValue const *x, GnmValue const *y)
+criteria_test_less_or_equal (GnmValue const *x, GnmValue const *y,
+			     GODateConventions const *date_conv)
 {
-	if (x == NULL || y == NULL)
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
+	case CRIT_STRING:
 		return FALSE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) <= value_get_as_float (y));
-	else
-		return FALSE;
+	case CRIT_FLOAT:
+		return xf <= yf;
+	}
 }
 
 static gboolean
-criteria_test_greater_or_equal (GnmValue const *x, GnmValue const *y)
+criteria_test_greater_or_equal (GnmValue const *x, GnmValue const *y,
+				GODateConventions const *date_conv)
 {
-	if (x == NULL || y == NULL)
+	gnm_float xf, yf;
+
+	switch (criteria_inspect_values (x, y, &xf, &yf, date_conv)) {
+	default:
+		g_assert_not_reached ();
+	case CRIT_NULL:
+	case CRIT_BADFLOAT:
+	case CRIT_STRING:
 		return FALSE;
-        if (VALUE_IS_NUMBER (x) && VALUE_IS_NUMBER (y))
-		return (value_get_as_float (x) >= value_get_as_float (y));
-	else
-		return FALSE;
+	case CRIT_FLOAT:
+		return xf >= yf;
+	}
 }
 
 /*
@@ -1641,6 +1713,8 @@
 	char const *t1, *t2;
 	GnmCell   *test_cell;
 	GnmCriteria const *cond;
+	GODateConventions const *date_conv =
+		workbook_date_conv (sheet->workbook);
 
 	for (row = first_row; row <= last_row; row++) {
 		add_flag = TRUE;
@@ -1653,7 +1727,7 @@
 				if (test_cell != NULL) {
 					gnm_cell_eval (test_cell);
 					if (!gnm_cell_is_empty (test_cell) &&
-					    !cond->fun (test_cell->value, cond->x)) {
+					    !cond->fun (test_cell->value, cond->x, date_conv)) {
 						add_flag = FALSE;
 						break;
 					}
Index: src/value.h
===================================================================
--- src/value.h	(revision 16471)
+++ src/value.h	(working copy)
@@ -186,7 +186,8 @@
 void value_array_set       (GnmValue *array, int col, int row, GnmValue *v);
 
 /* FIXME: this stuff below ought to go elsewhere.  */
-typedef gboolean (*GnmCriteriaFunc) (GnmValue const *x, GnmValue const *y);
+typedef gboolean (*GnmCriteriaFunc) (GnmValue const *x, GnmValue const *y,
+				     GODateConventions const *date_conv);
 typedef struct {
         GnmCriteriaFunc fun;
         GnmValue  *x;
Index: plugins/fn-database/functions.c
===================================================================
--- plugins/fn-database/functions.c	(revision 16471)
+++ plugins/fn-database/functions.c	(working copy)
@@ -28,6 +28,7 @@
 #include <str.h>
 #include <cell.h>
 #include <sheet.h>
+#include <workbook.h>
 #include <value.h>
 #include <number-match.h>
 #include <collect.h>
@@ -56,6 +57,8 @@
 	int    row, first_row, last_row;
 	gboolean add_flag;
 	GnmCell *cell;
+	GODateConventions const *date_conv =
+		workbook_date_conv (sheet->workbook);
 
 	cells = NULL;
 	/* TODO : Why ignore the first row ?  What if there is no header ? */
@@ -85,7 +88,7 @@
 				if (tmp != NULL)
 					gnm_cell_eval (tmp);
 				if (gnm_cell_is_empty (tmp) ||
-				    !cond->fun (tmp->value, cond->x)) {
+				    !cond->fun (tmp->value, cond->x, date_conv)) {
 					add_flag = FALSE;
 					break;
 				}
Index: plugins/fn-math/functions.c
===================================================================
--- plugins/fn-math/functions.c	(revision 16471)
+++ plugins/fn-math/functions.c	(working copy)
@@ -555,6 +555,7 @@
 typedef struct {
         GnmCriteriaFunc  test;
         GnmValue *test_value;
+	GODateConventions const *date_conv;
 	int count;
 } CountIfClosure;
 
@@ -566,7 +567,7 @@
 		gnm_cell_eval (cell);
 		if ((VALUE_IS_NUMBER (cell->value) ||
 		     VALUE_IS_STRING (cell->value)) &&
-		    (res->test) (cell->value, res->test_value))
+		    (res->test) (cell->value, res->test_value, res->date_conv))
 			res->count++;
 	}
 
@@ -592,6 +593,8 @@
 	    (!VALUE_IS_NUMBER (argv[1]) && !VALUE_IS_STRING (argv[1])))
 	        return value_new_error_VALUE (ei->pos);
 
+	res.date_conv = sheet ?	workbook_date_conv (sheet->workbook) : NULL;
+
 	res.count = 0;
 	parse_criteria (argv[1], &res.test, &res.test_value, &iter_flags,
 		workbook_date_conv (ei->pos->sheet->workbook));
@@ -636,6 +639,7 @@
 typedef struct {
         GnmCriteriaFunc  test;
         GnmValue            *test_value;
+	GODateConventions const *date_conv;
 
 	Sheet		*target_sheet;
 	GnmCellPos	 offset;
@@ -651,7 +655,7 @@
 	gnm_cell_eval (cell);
 
 	if ((VALUE_IS_NUMBER (cell->value) || VALUE_IS_STRING (cell->value)) &&
-	    (res->test) (cell->value, res->test_value)) {
+	    (res->test) (cell->value, res->test_value, res->date_conv)) {
 		if (NULL != res->target_sheet) {
 			cell = sheet_cell_get (res->target_sheet,
 				iter->pp.eval.col + res->offset.col,
@@ -695,6 +699,8 @@
 	    (!VALUE_IS_NUMBER (argv[1]) && !VALUE_IS_STRING (argv[1])))
 	        return value_new_error_VALUE (ei->pos);
 
+	res.date_conv = sheet ?	workbook_date_conv (sheet->workbook) : NULL;
+
 	col_end = r->cell.b.col;
 	row_end = r->cell.b.row;
 	if (NULL != argv[2]) {
