diff options
author | unknown <gkodinov/kgeorge@magare.gmz> | 2007-11-27 17:19:51 +0200 |
---|---|---|
committer | unknown <gkodinov/kgeorge@magare.gmz> | 2007-11-27 17:19:51 +0200 |
commit | 9d503cea20bc5f2e1569f16b0114d34dfd875d66 (patch) | |
tree | a3c420386343c1c165e1543cfd9788b34d0cb9bd | |
parent | 3058e0257315eeb183a1df10376cd9f4df3061fb (diff) | |
parent | 63b65169534c97f0c225859d2d6d49f3cee2bc10 (diff) | |
download | mariadb-git-9d503cea20bc5f2e1569f16b0114d34dfd875d66.tar.gz |
Merge magare.gmz:/home/kgeorge/mysql/work/B30355-5.0-opt
into magare.gmz:/home/kgeorge/mysql/work/B30355-5.1-opt
include/mysql_com.h:
Auto merged
mysql-test/r/udf.result:
Auto merged
mysql-test/t/udf.test:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/udf_example.c:
Auto merged
-rw-r--r-- | include/mysql_com.h | 4 | ||||
-rw-r--r-- | mysql-test/r/udf.result | 27 | ||||
-rw-r--r-- | mysql-test/t/udf.test | 21 | ||||
-rw-r--r-- | sql/item_func.cc | 6 | ||||
-rw-r--r-- | sql/item_func.h | 50 | ||||
-rw-r--r-- | sql/udf_example.c | 10 |
6 files changed, 112 insertions, 6 deletions
diff --git a/include/mysql_com.h b/include/mysql_com.h index 4ae7f66060f..d850c149bde 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -405,6 +405,10 @@ typedef struct st_udf_init my_bool const_item; void *extension; } 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 cb5afcf5f17..15410ac2039 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -365,4 +365,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 32cfca57546..e9ae1a31079 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -415,4 +415,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 809319d9056..e2551979202 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2961,6 +2961,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 4d7c96a18c1..87894810b7f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1022,6 +1022,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 6f2093cc92f..a3d149f0971 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; } |