From a699a5f967516bb2ed633fffc9539884e4df4499 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 22 Sep 2016 13:31:20 +0400 Subject: [PATCH] MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT --- mysql-test/r/keywords.result | 2 + .../suite/compat/oracle/r/func_decode.result | 2 +- mysql-test/suite/compat/oracle/r/sp.result | 174 ++++++++++++++++ mysql-test/suite/compat/oracle/t/sp.test | 190 ++++++++++++++++++ mysql-test/t/keywords.test | 3 + sql/item_func.cc | 15 ++ sql/item_func.h | 19 ++ sql/lex.h | 1 + sql/sql_yacc.yy | 2 + sql/sql_yacc_ora.yy | 10 + 10 files changed, 417 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result index d9b8d911ef4..231da5a86b6 100644 --- a/mysql-test/r/keywords.result +++ b/mysql-test/r/keywords.result @@ -348,3 +348,5 @@ CREATE TABLE varchar2 (varchar2 int); DROP TABLE varchar2; CREATE TABLE decode (decode int); DROP TABLE decode; +CREATE TABLE rowcount (rowcount int); +DROP TABLE rowcount; diff --git a/mysql-test/suite/compat/oracle/r/func_decode.result b/mysql-test/suite/compat/oracle/r/func_decode.result index a7c0ffdc264..c4bfb713e61 100644 --- a/mysql-test/suite/compat/oracle/r/func_decode.result +++ b/mysql-test/suite/compat/oracle/r/func_decode.result @@ -28,6 +28,6 @@ EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select (case 12 when 10 then 'x10' when 11 then 'x11' else 'def' end) AS "DECODE(12,10,'x10',11,'x11','def')" +Note 1003 select case 12 when 10 then 'x10' when 11 then 'x11' else 'def' end AS "DECODE(12,10,'x10',11,'x11','def')" CREATE TABLE decode (decode int); DROP TABLE decode; diff --git a/mysql-test/suite/compat/oracle/r/sp.result b/mysql-test/suite/compat/oracle/r/sp.result index ab6211939bb..893d9ff2225 100644 --- a/mysql-test/suite/compat/oracle/r/sp.result +++ b/mysql-test/suite/compat/oracle/r/sp.result @@ -1066,3 +1066,177 @@ END$$ CALL p1; ERROR 42S22: Unknown column 'unknown_ident' in 'field list' DROP PROCEDURE p1; +# +# MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT +# +EXPLAIN EXTENDED SELECT sql%rowcount; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select SQL%%ROWCOUNT AS "sql%rowcount" +CREATE TABLE t1 AS SELECT SQL%ROWCOUNT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "SQL%ROWCOUNT" bigint(21) NOT NULL +) +DROP TABLE t1; +# +# UPDATE +# +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1 +AS +BEGIN +UPDATE t1 SET a=30; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +0 +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +CREATE PROCEDURE p1 +AS +BEGIN +UPDATE t1 SET a=30; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +2 +DROP PROCEDURE p1; +DROP TABLE t1; +# +# DELETE +# +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1 +AS +BEGIN +DELETE FROM t1; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +0 +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +CREATE PROCEDURE p1 +AS +BEGIN +DELETE FROM t1; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +2 +DROP PROCEDURE p1; +DROP TABLE t1; +# +# SELECT ... INTO var FROM ... - one row found +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +CREATE PROCEDURE p1 +AS +va INT; +BEGIN +SELECT a INTO va FROM t1 LIMIT 1; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +1 +DROP PROCEDURE p1; +DROP TABLE t1; +# +# SELECT ... INTO var FROM ... - no rows found +# +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1 +AS +va INT; +BEGIN +SELECT a INTO va FROM t1; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +0 +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +DROP PROCEDURE p1; +DROP TABLE t1; +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p1 +AS +va INT; +BEGIN +SELECT a INTO va FROM t1; +SELECT SQL%ROWCOUNT; +EXCEPTION +WHEN NO_DATA_FOUND THEN SELECT SQL%ROWCOUNT||' (EXCEPTION)'; +END; +$$ +CALL p1(); +SQL%ROWCOUNT||' (EXCEPTION)' +0 (EXCEPTION) +DROP PROCEDURE p1; +DROP TABLE t1; +# +# SELECT ... INTO var FROM ... - multiple rows found +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +CREATE PROCEDURE p1 +AS +va INT:=1; +BEGIN +SELECT a INTO va FROM t1; +SELECT SQL%ROWCOUNT; +EXCEPTION +WHEN TOO_MANY_ROWS THEN SELECT SQL%ROWCOUNT||' (EXCEPTION) va='||va; +END; +$$ +CALL p1(); +SQL%ROWCOUNT||' (EXCEPTION) va='||va +1 (EXCEPTION) va=10 +DROP PROCEDURE p1; +DROP TABLE t1; +# +# INSERT INTO t2 SELECT ... +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +CREATE PROCEDURE p1 +AS +BEGIN +INSERT INTO t2 SELECT * FROM t1; +SELECT SQL%ROWCOUNT; +END; +$$ +CALL p1(); +SQL%ROWCOUNT +2 +DROP PROCEDURE p1; +DROP TABLE t1, t2; +# +# End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT +# diff --git a/mysql-test/suite/compat/oracle/t/sp.test b/mysql-test/suite/compat/oracle/t/sp.test index 3bdc1782a1a..e2298be3668 100644 --- a/mysql-test/suite/compat/oracle/t/sp.test +++ b/mysql-test/suite/compat/oracle/t/sp.test @@ -1158,3 +1158,193 @@ DELIMITER ;$$ --error ER_BAD_FIELD_ERROR CALL p1; DROP PROCEDURE p1; + +--echo # +--echo # MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT +--echo # + +EXPLAIN EXTENDED SELECT sql%rowcount; +CREATE TABLE t1 AS SELECT SQL%ROWCOUNT; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # UPDATE +--echo # + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + UPDATE t1 SET a=30; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + UPDATE t1 SET a=30; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +--echo # +--echo # DELETE +--echo # + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + DELETE FROM t1; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + DELETE FROM t1; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +--echo # +--echo # SELECT ... INTO var FROM ... - one row found +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +DELIMITER $$; +CREATE PROCEDURE p1 +AS + va INT; +BEGIN + SELECT a INTO va FROM t1 LIMIT 1; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +--echo # +--echo # SELECT ... INTO var FROM ... - no rows found +--echo # +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1 +AS + va INT; +BEGIN + SELECT a INTO va FROM t1; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +CREATE TABLE t1 (a INT); +DELIMITER $$; +CREATE PROCEDURE p1 +AS + va INT; +BEGIN + SELECT a INTO va FROM t1; + SELECT SQL%ROWCOUNT; +EXCEPTION + WHEN NO_DATA_FOUND THEN SELECT SQL%ROWCOUNT||' (EXCEPTION)'; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + +--echo # +--echo # SELECT ... INTO var FROM ... - multiple rows found +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +DELIMITER $$; +CREATE PROCEDURE p1 +AS + va INT:=1; +BEGIN + SELECT a INTO va FROM t1; + SELECT SQL%ROWCOUNT; +EXCEPTION + WHEN TOO_MANY_ROWS THEN SELECT SQL%ROWCOUNT||' (EXCEPTION) va='||va; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + + + +--echo # +--echo # INSERT INTO t2 SELECT ... +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (20); +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + INSERT INTO t2 SELECT * FROM t1; + SELECT SQL%ROWCOUNT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1, t2; + +--echo # +--echo # End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT +--echo # diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test index b9e52ab8308..de97aa58fd5 100644 --- a/mysql-test/t/keywords.test +++ b/mysql-test/t/keywords.test @@ -244,3 +244,6 @@ DROP TABLE varchar2; CREATE TABLE decode (decode int); DROP TABLE decode; + +CREATE TABLE rowcount (rowcount int); +DROP TABLE rowcount; diff --git a/sql/item_func.cc b/sql/item_func.cc index a7909155c5a..4dd3a1e7da4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6632,6 +6632,21 @@ longlong Item_func_found_rows::val_int() } +longlong Item_func_oracle_sql_rowcount::val_int() +{ + DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + /* + In case when a query like this: + INSERT a INTO @va FROM t1; + returns multiple rows, SQL%ROWCOUNT should report 1 rather than -1. + */ + longlong rows= thd->get_row_count_func(); + return rows != -1 ? rows : // ROW_COUNT() + thd->found_rows(); // FOUND_ROWS() +} + + /** @brief Checks if requested access to function can be granted to user. If function isn't found yet, it searches function first. diff --git a/sql/item_func.h b/sql/item_func.h index 26c2a484c57..274fadf4431 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2599,6 +2599,25 @@ public: }; +class Item_func_oracle_sql_rowcount :public Item_int_func +{ +public: + Item_func_oracle_sql_rowcount(THD *thd): Item_int_func(thd) {} + longlong val_int(); + const char *func_name() const { return "SQL%%ROWCOUNT"; } + void print(String *str, enum_query_type query_type) + { + str->append(func_name()); + } + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); + } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + + void uuid_short_init(); class Item_func_uuid_short :public Item_int_func diff --git a/sql/lex.h b/sql/lex.h index 8e946853c24..38b0e2ab68c 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -523,6 +523,7 @@ static SYMBOL symbols[] = { { "ROLLUP", SYM(ROLLUP_SYM)}, { "ROUTINE", SYM(ROUTINE_SYM)}, { "ROW", SYM(ROW_SYM)}, + { "ROWCOUNT", SYM(ROWCOUNT_SYM)}, /* Oracle-N */ { "ROWS", SYM(ROWS_SYM)}, { "ROW_COUNT", SYM(ROW_COUNT_SYM)}, { "ROW_FORMAT", SYM(ROW_FORMAT_SYM)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4edaa141326..d93cbd7ed61 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1409,6 +1409,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ROLLBACK_SYM /* SQL-2003-R */ %token ROLLUP_SYM /* SQL-2003-R */ %token ROUTINE_SYM /* SQL-2003-N */ +%token ROWCOUNT_SYM /* Oracle-N */ %token ROW_SYM /* SQL-2003-R */ %token ROWS_SYM /* SQL-2003-R */ %token ROW_COUNT_SYM /* SQL-2003-N */ @@ -14468,6 +14469,7 @@ keyword_sp: | ROLE_SYM {} | ROLLUP_SYM {} | ROUTINE_SYM {} + | ROWCOUNT_SYM {} | ROW_COUNT_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 71c160f4eda..d379991613b 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -783,6 +783,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ROLLBACK_SYM /* SQL-2003-R */ %token ROLLUP_SYM /* SQL-2003-R */ %token ROUTINE_SYM /* SQL-2003-N */ +%token ROWCOUNT_SYM /* Oracle-N */ %token ROW_SYM /* SQL-2003-R */ %token ROWS_SYM /* SQL-2003-R */ %token ROW_COUNT_SYM /* SQL-2003-N */ @@ -9075,6 +9076,14 @@ function_call_keyword: if ($$ == NULL) MYSQL_YYABORT; } + | SQL_SYM '%' ROWCOUNT_SYM + { + $$= new (thd->mem_root) Item_func_oracle_sql_rowcount(thd); + if ($$ == NULL) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } | TIME_SYM '(' expr ')' { $$= new (thd->mem_root) Item_time_typecast(thd, $3, @@ -14420,6 +14429,7 @@ keyword_sp: | ROLE_SYM {} | ROLLUP_SYM {} | ROUTINE_SYM {} + | ROWCOUNT_SYM {} | ROW_COUNT_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {}