summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <gkodinov/kgeorge@magare.gmz>2007-11-27 17:21:36 +0200
committerunknown <gkodinov/kgeorge@magare.gmz>2007-11-27 17:21:36 +0200
commitd0bfc6c13159aa5d619db21cd7ab1ebd2c0f759c (patch)
treec72b99e9f1bac5efc101d6074c5de3d3069b966f
parent29cdc47ecd3db062f2bf4dc88130da2a0299f6da (diff)
parent63b65169534c97f0c225859d2d6d49f3cee2bc10 (diff)
downloadmariadb-git-d0bfc6c13159aa5d619db21cd7ab1ebd2c0f759c.tar.gz
Merge gkodinov@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into magare.gmz:/home/kgeorge/mysql/autopush/B30355-5.0-opt
-rw-r--r--include/mysql_com.h4
-rw-r--r--mysql-test/r/udf.result27
-rw-r--r--mysql-test/t/udf.test21
-rw-r--r--sql/item_func.cc6
-rw-r--r--sql/item_func.h50
-rw-r--r--sql/udf_example.c10
6 files changed, 112 insertions, 6 deletions
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 889579e3622..fc03d98194b 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -393,6 +393,10 @@ typedef struct st_udf_init
char *ptr; /* free pointer for function data */
my_bool const_item; /* 0 if result is independent of arguments */
} UDF_INIT;
+/*
+ TODO: add a notion for determinism of the UDF.
+ See Item_udf_func::update_used_tables ()
+*/
/* Constants when using compression */
#define NET_HEADER_SIZE 4 /* standard header size */
diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result
index e6797796ea0..a79be1c3189 100644
--- a/mysql-test/r/udf.result
+++ b/mysql-test/r/udf.result
@@ -327,4 +327,31 @@ DROP FUNCTION check_const_len;
DROP PROCEDURE check_const_len_sp;
DROP TRIGGER check_const_len_trigger;
DROP TABLE const_len_bug;
+CREATE FUNCTION sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (4),(3),(2),(1);
+INSERT INTO t2 SELECT * FROM t1;
+SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC;
+seq a
+1 4
+2 3
+3 2
+4 1
+SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC;
+seq a
+4 1
+3 2
+2 3
+1 4
+SELECT * FROM t1 WHERE a = sequence();
+a
+SELECT * FROM t2 WHERE a = sequence();
+a
+1
+2
+3
+4
+DROP FUNCTION sequence;
+DROP TABLE t1,t2;
End of 5.0 tests.
diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test
index 22b8ed10a49..648494b3df9 100644
--- a/mysql-test/t/udf.test
+++ b/mysql-test/t/udf.test
@@ -362,4 +362,25 @@ DROP PROCEDURE check_const_len_sp;
DROP TRIGGER check_const_len_trigger;
DROP TABLE const_len_bug;
+
+#
+# Bug #30355: Incorrect ordering of UDF results
+#
+
+--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
+eval CREATE FUNCTION sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB";
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT PRIMARY KEY);
+INSERT INTO t1 VALUES (4),(3),(2),(1);
+INSERT INTO t2 SELECT * FROM t1;
+
+SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC;
+SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC;
+
+SELECT * FROM t1 WHERE a = sequence();
+SELECT * FROM t2 WHERE a = sequence();
+
+DROP FUNCTION sequence;
+DROP TABLE t1,t2;
+
--echo End of 5.0 tests.
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 264d9265bca..0309c1a17cb 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2968,6 +2968,12 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
func->max_length=min(initid.max_length,MAX_BLOB_WIDTH);
func->maybe_null=initid.maybe_null;
const_item_cache=initid.const_item;
+ /*
+ Keep used_tables_cache in sync with const_item_cache.
+ See the comment in Item_udf_func::update_used tables.
+ */
+ if (!const_item_cache && !used_tables_cache)
+ used_tables_cache= RAND_TABLE_BIT;
func->decimals=min(initid.decimals,NOT_FIXED_DEC);
}
initialized=1;
diff --git a/sql/item_func.h b/sql/item_func.h
index a31294c0395..734b215ddc0 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1016,6 +1016,56 @@ public:
fixed= 1;
return res;
}
+ void update_used_tables()
+ {
+ /*
+ TODO: Make a member in UDF_INIT and return if a UDF is deterministic or
+ not.
+ Currently UDF_INIT has a member (const_item) that is an in/out
+ parameter to the init() call.
+ The code in udf_handler::fix_fields also duplicates the arguments
+ handling code in Item_func::fix_fields().
+
+ The lack of information if a UDF is deterministic makes writing
+ a correct update_used_tables() for UDFs impossible.
+ One solution to this would be :
+ - Add a is_deterministic member of UDF_INIT
+ - (optionally) deprecate the const_item member of UDF_INIT
+ - Take away the duplicate code from udf_handler::fix_fields() and
+ make Item_udf_func call Item_func::fix_fields() to process its
+ arguments as for any other function.
+ - Store the deterministic flag returned by <udf>_init into the
+ udf_handler.
+ - Don't implement Item_udf_func::fix_fields, implement
+ Item_udf_func::fix_length_and_dec() instead (similar to non-UDF
+ functions).
+ - Override Item_func::update_used_tables to call
+ Item_func::update_used_tables() and add a RAND_TABLE_BIT to the
+ result of Item_func::update_used_tables() if the UDF is
+ non-deterministic.
+ - (optionally) rename RAND_TABLE_BIT to NONDETERMINISTIC_BIT to
+ better describe its usage.
+
+ The above would require a change of the UDF API.
+ Until that change is done here's how the current code works:
+ We call Item_func::update_used_tables() only when we know that
+ the function depends on real non-const tables and is deterministic.
+ This can be done only because we know that the optimizer will
+ call update_used_tables() only when there's possibly a new const
+ table. So update_used_tables() can only make a Item_func more
+ constant than it is currently.
+ That's why we don't need to do anything if a function is guaranteed
+ to return non-constant (it's non-deterministic) or is already a
+ const.
+ */
+ if ((used_tables_cache & ~PSEUDO_TABLE_BITS) &&
+ !(used_tables_cache & RAND_TABLE_BIT))
+ {
+ Item_func::update_used_tables();
+ if (!const_item_cache && !used_tables_cache)
+ used_tables_cache= RAND_TABLE_BIT;
+ }
+ }
void cleanup();
Item_result result_type () const { return udf.result_type(); }
table_map not_null_tables() const { return 0; }
diff --git a/sql/udf_example.c b/sql/udf_example.c
index df3a69755ad..4ca6133da03 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -648,13 +648,11 @@ my_bool sequence_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
return 1;
}
bzero(initid->ptr,sizeof(longlong));
- /*
- Fool MySQL to think that this function is a constant
- This will ensure that MySQL only evalutes the function
- when the rows are sent to the client and not before any ORDER BY
- clauses
+ /*
+ sequence() is a non-deterministic function : it has different value
+ even if called with the same arguments.
*/
- initid->const_item=1;
+ initid->const_item=0;
return 0;
}