mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/opt/local/work/mysql-5.0-15683
This commit is contained in:
commit
38bd424afa
16 changed files with 325 additions and 16 deletions
|
@ -880,3 +880,49 @@ select row_count();
|
|||
row_count()
|
||||
1
|
||||
drop table t1;
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 (a,b) values (2,8),(1,9),(3,7);
|
||||
prepare stmt from "select * from t1 order by ?";
|
||||
execute stmt using @a;
|
||||
a b
|
||||
2 8
|
||||
1 9
|
||||
3 7
|
||||
set @a=1;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
1 9
|
||||
2 8
|
||||
3 7
|
||||
set @a=2;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
3 7
|
||||
2 8
|
||||
1 9
|
||||
deallocate prepare stmt;
|
||||
select * from t1 order by 1;
|
||||
a b
|
||||
1 9
|
||||
2 8
|
||||
3 7
|
||||
prepare stmt from "select * from t1 order by ?+1";
|
||||
set @a=0;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
2 8
|
||||
1 9
|
||||
3 7
|
||||
set @a=1;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
2 8
|
||||
1 9
|
||||
3 7
|
||||
deallocate prepare stmt;
|
||||
select * from t1 order by 1+1;
|
||||
a b
|
||||
2 8
|
||||
1 9
|
||||
3 7
|
||||
drop table t1;
|
||||
|
|
|
@ -634,10 +634,18 @@ flush tables;
|
|||
return 5;
|
||||
end|
|
||||
ERROR 0A000: FLUSH is not allowed in stored function or trigger
|
||||
create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123()
|
||||
create procedure bug9529_901234567890123456789012345678901234567890123456789012345()
|
||||
begin
|
||||
end|
|
||||
ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' is too long
|
||||
ERROR 42000: Identifier name 'bug9529_901234567890123456789012345678901234567890123456789012345' is too long
|
||||
drop procedure if exists bug17015_0123456789012345678901234567890123456789012345678901234|
|
||||
create procedure bug17015_0123456789012345678901234567890123456789012345678901234()
|
||||
begin
|
||||
end|
|
||||
show procedure status like 'bug17015%'|
|
||||
Db Name Type Definer Modified Created Security_type Comment
|
||||
test bug17015_0123456789012345678901234567890123456789012345678901234 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
drop procedure bug17015_0123456789012345678901234567890123456789012345678901234|
|
||||
drop procedure if exists bug10969|
|
||||
create procedure bug10969()
|
||||
begin
|
||||
|
|
|
@ -214,3 +214,26 @@ drop function f1;
|
|||
drop function f2;
|
||||
drop function f3;
|
||||
drop procedure sp1;
|
||||
drop table if exists t1;
|
||||
drop view if exists v1, v2, v3;
|
||||
drop function if exists bug15683;
|
||||
create table t1 (f1 bigint, f2 varchar(20), f3 bigint);
|
||||
insert into t1 set f1 = 1, f2 = 'schoenenbourg', f3 = 1;
|
||||
create view v1 as select 1 from t1 union all select 1;
|
||||
create view v2 as select 1 from v1;
|
||||
create view v3 as select 1 as f1 from v2;
|
||||
create function bug15683() returns bigint
|
||||
begin
|
||||
return (select count(*) from v3);
|
||||
end|
|
||||
prepare stmt from "select bug15683()";
|
||||
execute stmt;
|
||||
bug15683()
|
||||
2
|
||||
execute stmt;
|
||||
bug15683()
|
||||
2
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
drop view v1, v2, v3;
|
||||
drop function bug15683;
|
||||
|
|
|
@ -4802,4 +4802,39 @@ f1 bug13575(f1)
|
|||
3 ccc
|
||||
drop function bug13575;
|
||||
drop table t3|
|
||||
drop procedure if exists bug16474_1|
|
||||
drop procedure if exists bug16474_2|
|
||||
delete from t1|
|
||||
insert into t1 values ('c', 2), ('b', 3), ('a', 1)|
|
||||
create procedure bug16474_1()
|
||||
begin
|
||||
declare x int;
|
||||
select id from t1 order by x;
|
||||
end|
|
||||
create procedure bug16474_2(x int)
|
||||
select id from t1 order by x|
|
||||
call bug16474_1()|
|
||||
id
|
||||
c
|
||||
b
|
||||
a
|
||||
call bug16474_2(1)|
|
||||
id
|
||||
c
|
||||
b
|
||||
a
|
||||
call bug16474_2(2)|
|
||||
id
|
||||
c
|
||||
b
|
||||
a
|
||||
drop procedure bug16474_1|
|
||||
drop procedure bug16474_2|
|
||||
set @x = 2|
|
||||
select * from t1 order by @x|
|
||||
id data
|
||||
c 2
|
||||
b 3
|
||||
a 1
|
||||
delete from t1|
|
||||
drop table t1,t2;
|
||||
|
|
|
@ -2,6 +2,7 @@ drop table if exists t1, t2, t3, t4;
|
|||
drop view if exists v1;
|
||||
drop database if exists mysqltest;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
drop procedure if exists p1;
|
||||
create table t1 (i int);
|
||||
create trigger trg before insert on t1 for each row set @a:=1;
|
||||
|
@ -928,3 +929,26 @@ create trigger t1_bi before insert on t1 for each row return 0;
|
|||
ERROR 42000: RETURN is only allowed in a FUNCTION
|
||||
insert into t1 values (1);
|
||||
drop table t1;
|
||||
create table t1 (a varchar(64), b int);
|
||||
create table t2 like t1;
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
set @a:= (select max(a) from t1);
|
||||
insert into t1 (a) values
|
||||
("Twas"),("brillig"),("and"),("the"),("slithy"),("toves"),
|
||||
("Did"),("gyre"),("and"),("gimble"),("in"),("the"),("wabe");
|
||||
create trigger t2_ai after insert on t2 for each row
|
||||
set @a:= (select max(a) from t2);
|
||||
insert into t2 select * from t1;
|
||||
load data infile '../std_data_ln/words.dat' into table t1 (a);
|
||||
drop trigger t1_ai;
|
||||
drop trigger t2_ai;
|
||||
create function f1() returns int return (select max(b) from t1);
|
||||
insert into t1 values
|
||||
("All",f1()),("mimsy",f1()),("were",f1()),("the",f1()),("borogoves",f1()),
|
||||
("And",f1()),("the",f1()),("mome", f1()),("raths",f1()),("outgrabe",f1());
|
||||
create function f2() returns int return (select max(b) from t2);
|
||||
insert into t2 select a, f2() from t1;
|
||||
load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
|
||||
drop table t1;
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
|
|
|
@ -933,4 +933,38 @@ execute ins_call;
|
|||
select row_count();
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# BUG#16474: SP crashed MySQL
|
||||
# (when using "order by localvar", where 'localvar' is just that.
|
||||
# The actual bug test is in sp.test, this is just testing that we get the
|
||||
# expected result for prepared statements too, i.e. place holders work as
|
||||
# textual substitution. If it's a single integer, it works as the (deprecated)
|
||||
# "order by column#", otherwise it's an expression.
|
||||
#
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 (a,b) values (2,8),(1,9),(3,7);
|
||||
|
||||
# Will order by index
|
||||
prepare stmt from "select * from t1 order by ?";
|
||||
execute stmt using @a;
|
||||
set @a=1;
|
||||
execute stmt using @a;
|
||||
set @a=2;
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
# For reference:
|
||||
select * from t1 order by 1;
|
||||
|
||||
# Will not order by index.
|
||||
prepare stmt from "select * from t1 order by ?+1";
|
||||
set @a=0;
|
||||
execute stmt using @a;
|
||||
set @a=1;
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
# For reference:
|
||||
select * from t1 order by 1+1;
|
||||
|
||||
drop table t1;
|
||||
|
||||
# End of 5.0 tests
|
||||
|
|
|
@ -904,12 +904,26 @@ end|
|
|||
#
|
||||
# BUG#9529: Stored Procedures: No Warning on truncation of procedure name
|
||||
# during creation.
|
||||
# Note: When using utf8 for mysql.proc, this limit is much higher than before
|
||||
# BUG#17015: Routine name truncation not an error
|
||||
# When we started using utf8 for mysql.proc, this limit appeared
|
||||
# to be higher, but in reality the names were truncated.
|
||||
--error ER_TOO_LONG_IDENT
|
||||
create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123()
|
||||
create procedure bug9529_901234567890123456789012345678901234567890123456789012345()
|
||||
begin
|
||||
end|
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists bug17015_0123456789012345678901234567890123456789012345678901234|
|
||||
--enable_warnings
|
||||
# Check the upper limit, just to make sure.
|
||||
create procedure bug17015_0123456789012345678901234567890123456789012345678901234()
|
||||
begin
|
||||
end|
|
||||
|
||||
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
|
||||
show procedure status like 'bug17015%'|
|
||||
drop procedure bug17015_0123456789012345678901234567890123456789012345678901234|
|
||||
|
||||
|
||||
#
|
||||
# BUG#10969: Stored procedures: crash if default() function
|
||||
|
@ -1699,4 +1713,3 @@ create aggregate function bug16896() returns int return 1;
|
|||
#drop procedure if exists bugNNNN|
|
||||
#--enable_warnings
|
||||
#create procedure bugNNNN...
|
||||
|
||||
|
|
|
@ -241,3 +241,34 @@ drop function f2;
|
|||
drop function f3;
|
||||
drop procedure sp1;
|
||||
|
||||
#
|
||||
# Bug#15683 "crash, Function on nested VIEWs, Prepared statement"
|
||||
# Check that when creating the prelocking list a nested view
|
||||
# is not merged until it's used.
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
drop view if exists v1, v2, v3;
|
||||
drop function if exists bug15683;
|
||||
--enable_warnings
|
||||
create table t1 (f1 bigint, f2 varchar(20), f3 bigint);
|
||||
insert into t1 set f1 = 1, f2 = 'schoenenbourg', f3 = 1;
|
||||
create view v1 as select 1 from t1 union all select 1;
|
||||
create view v2 as select 1 from v1;
|
||||
create view v3 as select 1 as f1 from v2;
|
||||
|
||||
delimiter |;
|
||||
create function bug15683() returns bigint
|
||||
begin
|
||||
return (select count(*) from v3);
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
prepare stmt from "select bug15683()";
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
drop view v1, v2, v3;
|
||||
drop function bug15683;
|
||||
|
||||
|
|
|
@ -5647,6 +5647,42 @@ select distinct f1, bug13575(f1) from t3 order by f1|
|
|||
drop function bug13575;
|
||||
drop table t3|
|
||||
|
||||
#
|
||||
# BUG#16474: SP crashed MySQL
|
||||
# (when using "order by localvar", where 'localvar' is just that.
|
||||
#
|
||||
--disable_warnings
|
||||
drop procedure if exists bug16474_1|
|
||||
drop procedure if exists bug16474_2|
|
||||
--enable_warnings
|
||||
|
||||
delete from t1|
|
||||
insert into t1 values ('c', 2), ('b', 3), ('a', 1)|
|
||||
|
||||
create procedure bug16474_1()
|
||||
begin
|
||||
declare x int;
|
||||
|
||||
select id from t1 order by x;
|
||||
end|
|
||||
|
||||
# This does NOT order by column index; variable is an expression.
|
||||
create procedure bug16474_2(x int)
|
||||
select id from t1 order by x|
|
||||
|
||||
call bug16474_1()|
|
||||
call bug16474_2(1)|
|
||||
call bug16474_2(2)|
|
||||
drop procedure bug16474_1|
|
||||
drop procedure bug16474_2|
|
||||
|
||||
# For reference: user variables are expressions too and do not affect ordering.
|
||||
set @x = 2|
|
||||
select * from t1 order by @x|
|
||||
|
||||
delete from t1|
|
||||
|
||||
|
||||
#
|
||||
# BUG#NNNN: New bug synopsis
|
||||
#
|
||||
|
|
|
@ -7,6 +7,7 @@ drop table if exists t1, t2, t3, t4;
|
|||
drop view if exists v1;
|
||||
drop database if exists mysqltest;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
drop procedure if exists p1;
|
||||
--enable_warnings
|
||||
|
||||
|
@ -1080,3 +1081,36 @@ create table t1 (i int);
|
|||
create trigger t1_bi before insert on t1 for each row return 0;
|
||||
insert into t1 values (1);
|
||||
drop table t1;
|
||||
|
||||
# Test for bug #17764 "Trigger crashes MyISAM table"
|
||||
#
|
||||
# Table was reported as crashed when it was subject table of trigger invoked
|
||||
# by insert statement which was executed with enabled bulk insert mode (which
|
||||
# is actually set of optimizations enabled by handler::start_bulk_insert())
|
||||
# and this trigger also explicitly referenced it.
|
||||
# The same problem arose when table to which bulk insert was done was also
|
||||
# referenced in function called by insert statement.
|
||||
create table t1 (a varchar(64), b int);
|
||||
create table t2 like t1;
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
set @a:= (select max(a) from t1);
|
||||
insert into t1 (a) values
|
||||
("Twas"),("brillig"),("and"),("the"),("slithy"),("toves"),
|
||||
("Did"),("gyre"),("and"),("gimble"),("in"),("the"),("wabe");
|
||||
create trigger t2_ai after insert on t2 for each row
|
||||
set @a:= (select max(a) from t2);
|
||||
insert into t2 select * from t1;
|
||||
load data infile '../std_data_ln/words.dat' into table t1 (a);
|
||||
drop trigger t1_ai;
|
||||
drop trigger t2_ai;
|
||||
# Test that the problem for functions is fixed as well
|
||||
create function f1() returns int return (select max(b) from t1);
|
||||
insert into t1 values
|
||||
("All",f1()),("mimsy",f1()),("were",f1()),("the",f1()),("borogoves",f1()),
|
||||
("And",f1()),("the",f1()),("mome", f1()),("raths",f1()),("outgrabe",f1());
|
||||
create function f2() returns int return (select max(b) from t2);
|
||||
insert into t2 select a, f2() from t1;
|
||||
load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
|
||||
drop table t1;
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
|
|
|
@ -320,6 +320,12 @@ public:
|
|||
/* convert decimal to longlong with overflow check */
|
||||
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
|
||||
int *err);
|
||||
/* The max. number of characters */
|
||||
inline uint32 Field::char_length() const
|
||||
{
|
||||
return field_length / charset()->mbmaxlen;
|
||||
}
|
||||
|
||||
friend bool reopen_table(THD *,struct st_table *,bool);
|
||||
friend int cre_myisam(my_string name, register TABLE *form, uint options,
|
||||
ulonglong auto_increment_value);
|
||||
|
|
|
@ -534,7 +534,11 @@ db_create_routine(THD *thd, int type, sp_head *sp)
|
|||
ret= SP_GET_FIELD_FAILED;
|
||||
goto done;
|
||||
}
|
||||
if (sp->m_name.length > table->field[MYSQL_PROC_FIELD_NAME]->field_length)
|
||||
|
||||
if (system_charset_info->cset->numchars(system_charset_info,
|
||||
sp->m_name.str,
|
||||
sp->m_name.str+sp->m_name.length) >
|
||||
table->field[MYSQL_PROC_FIELD_NAME]->char_length())
|
||||
{
|
||||
ret= SP_BAD_IDENTIFIER;
|
||||
goto done;
|
||||
|
|
|
@ -405,11 +405,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||
let's *try* to start bulk inserts. It won't necessary
|
||||
start them as values_list.elements should be greater than
|
||||
some - handler dependent - threshold.
|
||||
We should not start bulk inserts if this statement uses
|
||||
functions or invokes triggers since they may access
|
||||
to the same table and therefore should not see its
|
||||
inconsistent state created by this optimization.
|
||||
So we call start_bulk_insert to perform nesessary checks on
|
||||
values_list.elements, and - if nothing else - to initialize
|
||||
the code to make the call of end_bulk_insert() below safe.
|
||||
*/
|
||||
if (lock_type != TL_WRITE_DELAYED)
|
||||
if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
|
||||
table->file->start_bulk_insert(values_list.elements);
|
||||
|
||||
thd->no_trans_update= 0;
|
||||
|
@ -535,7 +539,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
if (table->file->end_bulk_insert() && !error)
|
||||
if (!thd->prelocked_mode && table->file->end_bulk_insert() && !error)
|
||||
{
|
||||
table->file->print_error(my_errno,MYF(0));
|
||||
error=1;
|
||||
|
@ -2190,7 +2194,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
lex->current_select->options|= OPTION_BUFFER_RESULT;
|
||||
lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
else
|
||||
else if (!thd->prelocked_mode)
|
||||
{
|
||||
/*
|
||||
We must not yet prepare the result table if it is the same as one of the
|
||||
|
@ -2198,6 +2202,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
indexes on the result table, which may be used during the select, if it
|
||||
is the same table (Bug #6034). Do the preparation after the select phase
|
||||
in select_insert::prepare2().
|
||||
We won't start bulk inserts at all if this statement uses functions or
|
||||
should invoke triggers since they may access to the same table too.
|
||||
*/
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
}
|
||||
|
@ -2238,7 +2244,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
int select_insert::prepare2(void)
|
||||
{
|
||||
DBUG_ENTER("select_insert::prepare2");
|
||||
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT)
|
||||
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
|
||||
!thd->prelocked_mode)
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -2341,7 +2348,8 @@ void select_insert::send_error(uint errcode,const char *err)
|
|||
*/
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
table->file->end_bulk_insert();
|
||||
if (!thd->prelocked_mode)
|
||||
table->file->end_bulk_insert();
|
||||
/*
|
||||
If at least one row has been inserted/modified and will stay in the table
|
||||
(the table doesn't have transactions) (example: we got a duplicate key
|
||||
|
@ -2376,7 +2384,7 @@ bool select_insert::send_eof()
|
|||
int error,error2;
|
||||
DBUG_ENTER("select_insert::send_eof");
|
||||
|
||||
error=table->file->end_bulk_insert();
|
||||
error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
|
||||
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
|
||||
/*
|
||||
|
@ -2459,7 +2467,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
thd->cuted_fields=0;
|
||||
if (info.ignore || info.handle_duplicates != DUP_ERROR)
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
if (!thd->prelocked_mode)
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
thd->no_trans_update= 0;
|
||||
thd->abort_on_warning= (!info.ignore &&
|
||||
(thd->variables.sql_mode &
|
||||
|
|
|
@ -356,7 +356,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||
if (ignore ||
|
||||
handle_duplicates == DUP_REPLACE)
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
if (!thd->prelocked_mode)
|
||||
table->file->start_bulk_insert((ha_rows) 0);
|
||||
table->copy_blobs=1;
|
||||
|
||||
thd->no_trans_update= 0;
|
||||
|
@ -373,7 +374,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||
error= read_sep_field(thd, info, table_list, fields_vars,
|
||||
set_fields, set_values, read_info,
|
||||
*enclosed, skip_lines, ignore);
|
||||
if (table->file->end_bulk_insert() && !error)
|
||||
if (!thd->prelocked_mode && table->file->end_bulk_insert() && !error)
|
||||
{
|
||||
table->file->print_error(my_errno, MYF(0));
|
||||
error= 1;
|
||||
|
|
|
@ -12333,7 +12333,11 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
|||
Item **select_item; /* The corresponding item from the SELECT clause. */
|
||||
Field *from_field; /* The corresponding field from the FROM clause. */
|
||||
|
||||
if (order_item->type() == Item::INT_ITEM)
|
||||
/*
|
||||
Local SP variables may be int but are expressions, not positions.
|
||||
(And they can't be used before fix_fields is called for them).
|
||||
*/
|
||||
if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item())
|
||||
{ /* Order by position */
|
||||
uint count= (uint) order_item->val_int();
|
||||
if (!count || count > fields.elements)
|
||||
|
|
|
@ -938,6 +938,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
|
|||
tbl->skip_temporary= 1;
|
||||
tbl->belong_to_view= top_view;
|
||||
tbl->referencing_view= table;
|
||||
tbl->prelocking_placeholder= table->prelocking_placeholder;
|
||||
/*
|
||||
First we fill want_privilege with SELECT_ACL (this is needed for the
|
||||
tables which belongs to view subqueries and temporary table views,
|
||||
|
|
Loading…
Reference in a new issue