mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Added function last_value() which returns the last value but evalutes all arguments as a side effect.
Original patch by Eric Herman client/mysql.cc: Added LAST_VALUE mysql-test/r/last_value.result: Testing of LAST_VALUE mysql-test/t/last_value.test: Testing of LAST_VALUE sql/item_func.cc: Added LAST_VALUE() sql/item_func.h: Added LAST_VALUE() sql/lex.h: Added LAST_VALUE() sql/sql_yacc.yy: Added LAST_VALUE()
This commit is contained in:
@ -897,6 +897,7 @@ static COMMANDS commands[] = {
|
|||||||
{ "LAST_INSERT_ID", 0, 0, 0, ""},
|
{ "LAST_INSERT_ID", 0, 0, 0, ""},
|
||||||
{ "ISSIMPLE", 0, 0, 0, ""},
|
{ "ISSIMPLE", 0, 0, 0, ""},
|
||||||
{ "LAST_DAY", 0, 0, 0, ""},
|
{ "LAST_DAY", 0, 0, 0, ""},
|
||||||
|
{ "LAST_VALUE", 0, 0, 0, ""},
|
||||||
{ "LCASE", 0, 0, 0, ""},
|
{ "LCASE", 0, 0, 0, ""},
|
||||||
{ "LEAST", 0, 0, 0, ""},
|
{ "LEAST", 0, 0, 0, ""},
|
||||||
{ "LENGTH", 0, 0, 0, ""},
|
{ "LENGTH", 0, 0, 0, ""},
|
||||||
|
73
mysql-test/r/last_value.result
Normal file
73
mysql-test/r/last_value.result
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
drop table if exists t1;
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
CREATE TABLE t1 (a INT, b INT, c INT, d INT);
|
||||||
|
INSERT INTO t1 VALUES (1,3,0,NULL),(2,2,0,NULL),(3,4,0,NULL),(4,2,0,NULL);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a b c d
|
||||||
|
1 3 0 NULL
|
||||||
|
2 2 0 NULL
|
||||||
|
3 4 0 NULL
|
||||||
|
4 2 0 NULL
|
||||||
|
UPDATE t1 SET c=LAST_VALUE(@last_a:=a,@last_b:=b,@last_c:=c,1), d=4211 WHERE c=0 ORDER BY b DESC LIMIT 1;
|
||||||
|
SELECT @last_a, @last_b, @last_c;
|
||||||
|
@last_a @last_b @last_c
|
||||||
|
3 4 0
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a b c d
|
||||||
|
1 3 0 NULL
|
||||||
|
2 2 0 NULL
|
||||||
|
3 4 1 4211
|
||||||
|
4 2 0 NULL
|
||||||
|
DROP TABLE t1;
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:=1);
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def LAST_VALUE(@last_a:=1,@last_b:=1) 8 1 1 N 32897 0 63
|
||||||
|
LAST_VALUE(@last_a:=1,@last_b:=1)
|
||||||
|
1
|
||||||
|
select @last_b;
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def @last_b 8 20 1 Y 32896 0 63
|
||||||
|
@last_b
|
||||||
|
1
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:=1.0);
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def LAST_VALUE(@last_a:=1,@last_b:=1.0) 246 4 3 N 32897 1 63
|
||||||
|
LAST_VALUE(@last_a:=1,@last_b:=1.0)
|
||||||
|
1.0
|
||||||
|
select @last_b;
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def @last_b 246 83 3 Y 32896 30 63
|
||||||
|
@last_b
|
||||||
|
1.0
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:="hello");
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def LAST_VALUE(@last_a:=1,@last_b:="hello") 253 5 5 N 1 31 8
|
||||||
|
LAST_VALUE(@last_a:=1,@last_b:="hello")
|
||||||
|
hello
|
||||||
|
select @last_b;
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def @last_b 250 16777215 5 Y 0 31 8
|
||||||
|
@last_b
|
||||||
|
hello
|
||||||
|
SELECT date(LAST_VALUE(@last_a:=1,@last_b:="2001-02-03"));
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def date(LAST_VALUE(@last_a:=1,@last_b:="2001-02-03")) 10 10 10 Y 128 0 63
|
||||||
|
date(LAST_VALUE(@last_a:=1,@last_b:="2001-02-03"))
|
||||||
|
2001-02-03
|
||||||
|
select @last_b;
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def @last_b 250 16777215 10 Y 0 31 8
|
||||||
|
@last_b
|
||||||
|
2001-02-03
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:="2001-02-03",NULL);
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def LAST_VALUE(@last_a:=1,@last_b:="2001-02-03",NULL) 6 0 0 Y 32896 0 63
|
||||||
|
LAST_VALUE(@last_a:=1,@last_b:="2001-02-03",NULL)
|
||||||
|
NULL
|
||||||
|
select @last_b;
|
||||||
|
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||||
|
def @last_b 250 16777215 10 Y 0 31 8
|
||||||
|
@last_b
|
||||||
|
2001-02-03
|
||||||
|
SELECT LAST_VALUE();
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ')' at line 1
|
43
mysql-test/t/last_value.test
Normal file
43
mysql-test/t/last_value.test
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Tests for the LAST_VALUE function
|
||||||
|
#
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
# CREATE TABLE `queue` (
|
||||||
|
# `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
# `priority` int(11) DEFAULT NULL,
|
||||||
|
# `state` int(11) DEFAULT NULL,
|
||||||
|
# `pid` int(10) unsigned DEFAULT NULL,
|
||||||
|
# `dat` varbinary(200) DEFAULT NULL,
|
||||||
|
# PRIMARY KEY (`id`)
|
||||||
|
# )
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT, b INT, c INT, d INT);
|
||||||
|
INSERT INTO t1 VALUES (1,3,0,NULL),(2,2,0,NULL),(3,4,0,NULL),(4,2,0,NULL);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
UPDATE t1 SET c=LAST_VALUE(@last_a:=a,@last_b:=b,@last_c:=c,1), d=4211 WHERE c=0 ORDER BY b DESC LIMIT 1;
|
||||||
|
SELECT @last_a, @last_b, @last_c;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test with different types
|
||||||
|
#
|
||||||
|
--enable_metadata
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:=1);
|
||||||
|
select @last_b;
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:=1.0);
|
||||||
|
select @last_b;
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:="hello");
|
||||||
|
select @last_b;
|
||||||
|
SELECT date(LAST_VALUE(@last_a:=1,@last_b:="2001-02-03"));
|
||||||
|
select @last_b;
|
||||||
|
SELECT LAST_VALUE(@last_a:=1,@last_b:="2001-02-03",NULL);
|
||||||
|
select @last_b;
|
||||||
|
--disable_metadata
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
SELECT LAST_VALUE();
|
@ -6816,3 +6816,62 @@ longlong Item_func_uuid_short::val_int()
|
|||||||
mysql_mutex_unlock(&LOCK_short_uuid_generator);
|
mysql_mutex_unlock(&LOCK_short_uuid_generator);
|
||||||
return (longlong) val;
|
return (longlong) val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Last_value - return last argument.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Item_func_last_value::evaluate_sideeffects()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed == 1 && arg_count > 0);
|
||||||
|
for (uint i= 0; i < arg_count-1 ; i++)
|
||||||
|
args[i]->val_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
String *Item_func_last_value::val_str(String *str)
|
||||||
|
{
|
||||||
|
String *tmp;
|
||||||
|
evaluate_sideeffects();
|
||||||
|
tmp= last_value->val_str(str);
|
||||||
|
null_value= last_value->null_value;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Item_func_last_value::val_int()
|
||||||
|
{
|
||||||
|
longlong tmp;
|
||||||
|
evaluate_sideeffects();
|
||||||
|
tmp= last_value->val_int();
|
||||||
|
null_value= last_value->null_value;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Item_func_last_value::val_real()
|
||||||
|
{
|
||||||
|
double tmp;
|
||||||
|
evaluate_sideeffects();
|
||||||
|
tmp= last_value->val_real();
|
||||||
|
null_value= last_value->null_value;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value)
|
||||||
|
{
|
||||||
|
my_decimal *tmp;
|
||||||
|
evaluate_sideeffects();
|
||||||
|
tmp= last_value->val_decimal(decimal_value);
|
||||||
|
null_value= last_value->null_value;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_func_last_value::fix_length_and_dec()
|
||||||
|
{
|
||||||
|
last_value= args[arg_count -1];
|
||||||
|
decimals= last_value->decimals;
|
||||||
|
max_length= last_value->max_length;
|
||||||
|
collation.set(last_value->collation.collation);
|
||||||
|
maybe_null= last_value->maybe_null;
|
||||||
|
unsigned_flag= last_value->unsigned_flag;
|
||||||
|
}
|
||||||
|
@ -2003,6 +2003,27 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_func_last_value :public Item_func
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Item *last_value;
|
||||||
|
public:
|
||||||
|
Item_func_last_value(List<Item> &list) :Item_func(list) {}
|
||||||
|
double val_real();
|
||||||
|
longlong val_int();
|
||||||
|
String *val_str(String *);
|
||||||
|
my_decimal *val_decimal(my_decimal *);
|
||||||
|
void fix_length_and_dec();
|
||||||
|
enum Item_result result_type () const { return last_value->result_type(); }
|
||||||
|
const char *func_name() const { return "last_value"; }
|
||||||
|
table_map not_null_tables() const { return 0; }
|
||||||
|
enum_field_types field_type() const { return last_value->field_type(); }
|
||||||
|
bool const_item() const { return 0; }
|
||||||
|
void evaluate_sideeffects();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
|
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
|
||||||
LEX_STRING component);
|
LEX_STRING component);
|
||||||
extern bool check_reserved_words(LEX_STRING *name);
|
extern bool check_reserved_words(LEX_STRING *name);
|
||||||
|
@ -302,6 +302,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "KILL", SYM(KILL_SYM)},
|
{ "KILL", SYM(KILL_SYM)},
|
||||||
{ "LANGUAGE", SYM(LANGUAGE_SYM)},
|
{ "LANGUAGE", SYM(LANGUAGE_SYM)},
|
||||||
{ "LAST", SYM(LAST_SYM)},
|
{ "LAST", SYM(LAST_SYM)},
|
||||||
|
{ "LAST_VALUE", SYM(LAST_VALUE)},
|
||||||
{ "LEADING", SYM(LEADING)},
|
{ "LEADING", SYM(LEADING)},
|
||||||
{ "LEAVE", SYM(LEAVE_SYM)},
|
{ "LEAVE", SYM(LEAVE_SYM)},
|
||||||
{ "LEAVES", SYM(LEAVES)},
|
{ "LEAVES", SYM(LEAVES)},
|
||||||
|
@ -1064,6 +1064,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
|||||||
%token KILL_SYM
|
%token KILL_SYM
|
||||||
%token LANGUAGE_SYM /* SQL-2003-R */
|
%token LANGUAGE_SYM /* SQL-2003-R */
|
||||||
%token LAST_SYM /* SQL-2003-N */
|
%token LAST_SYM /* SQL-2003-N */
|
||||||
|
%token LAST_VALUE
|
||||||
%token LE /* OPERATOR */
|
%token LE /* OPERATOR */
|
||||||
%token LEADING /* SQL-2003-R */
|
%token LEADING /* SQL-2003-R */
|
||||||
%token LEAVES
|
%token LEAVES
|
||||||
@ -8890,6 +8891,12 @@ function_call_conflict:
|
|||||||
if ($$ == NULL)
|
if ($$ == NULL)
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
|
| LAST_VALUE '(' expr_list ')'
|
||||||
|
{
|
||||||
|
$$= new (YYTHD->mem_root) Item_func_last_value(* $3);
|
||||||
|
if ($$ == NULL)
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
| MICROSECOND_SYM '(' expr ')'
|
| MICROSECOND_SYM '(' expr ')'
|
||||||
{
|
{
|
||||||
$$= new (YYTHD->mem_root) Item_func_microsecond($3);
|
$$= new (YYTHD->mem_root) Item_func_microsecond($3);
|
||||||
@ -13088,6 +13095,7 @@ keyword_sp:
|
|||||||
| ISSUER_SYM {}
|
| ISSUER_SYM {}
|
||||||
| INSERT_METHOD {}
|
| INSERT_METHOD {}
|
||||||
| KEY_BLOCK_SIZE {}
|
| KEY_BLOCK_SIZE {}
|
||||||
|
| LAST_VALUE {}
|
||||||
| LAST_SYM {}
|
| LAST_SYM {}
|
||||||
| LEAVES {}
|
| LEAVES {}
|
||||||
| LESS_SYM {}
|
| LESS_SYM {}
|
||||||
|
Reference in New Issue
Block a user