Commit 5188f031 authored by unknown's avatar unknown

Patch two (the final one) for Bug#7306 "the server side preparedStatement

 error for LIMIT placeholder".
The patch adds grammar support for LIMIT ?, ? and changes the
type of ST_SELECT_LEX::select_limit,offset_limit from ha_rows to Item*,
so that it can point to Item_param.


mysql-test/include/ps_modify.inc:
  Fix existing tests: now LIMIT can contain placeholders.
mysql-test/include/ps_query.inc:
  Fix existing tests: now LIMIT can contain placeholders.
mysql-test/r/ps.result:
  Add basic test coverage for LIMIT ?, ? and fix test results.
mysql-test/r/ps_2myisam.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/r/ps_3innodb.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/r/ps_4heap.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/r/ps_5merge.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/r/ps_6bdb.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/r/ps_7ndb.result:
  Fix test results: now LIMIT can contain placeholders.
mysql-test/t/ps.test:
  Add basic test coverage for LIMIT ?, ?.
sql/item.h:
  Add a short-cut for (ulonglong) val_int() to Item.
  Add a constructor to Item_int() that accepts ulonglong.
  Simplify Item_uint constructor by using the c-tor above.
sql/item_subselect.cc:
  Now select_limit has type Item *.
  We can safely create an Item in Item_exists_subselect::fix_length_and_dec():
  it will be allocated in runtime memory root and freed in the end of
  execution.
sql/sp_head.cc:
  Add a special initalization state for stored procedures to 
  be able to easily distinguish the first execution of a stored procedure
  from prepared statement prepare.
sql/sql_class.h:
  Introduce new state 'INITIALIZED_FOR_SP' to be able to easily distinguish
  the first execution of a stored procedure from prepared statement prepare.
sql/sql_derived.cc:
  - use unit->set_limit() to set unit->select_limit_cnt, offset_limit_cnt
    evreryplace. Add a warning about use of set_limit in 
  mysql_derived_filling.
sql/sql_error.cc:
  - use unit->set_limit() to set unit->select_limit_cnt, offset_limit_cnt
    evreryplace.
  - this change is also aware of bug#11095 "show warnings limit 0 returns 
  all rows instead of zero rows", so the one who merges the bugfix from
  4.1 can use local version of sql_error.cc.
sql/sql_handler.cc:
  - use unit->set_limit() to initalize 
  unit->select_limit_cnt,offset_limit_cnt everyplace.
sql/sql_lex.cc:
  Now ST_SELECT_LEX::select_limit, offset_limit have type Item *
sql/sql_lex.h:
  Now ST_SELECT_LEX::select_limit, offset_limit have type Item *
sql/sql_parse.cc:
  - use unit->set_limit() to initalize 
  unit->select_limit_cnt,offset_limit_cnt everyplace. 
  - we can create an Item_int to set global limit of a statement:
  it will be created in the runtime mem root and freed in the end of
  execution.
sql/sql_repl.cc:
  Use unit->set_limit to initialize limits.
sql/sql_select.cc:
  - select_limit is now Item* so the proper way to check for default value
  is to compare it with NULL.
sql/sql_union.cc:
  Evaluate offset_limit_cnt using the new type of ST_SELECT_LEX::offset_limit
sql/sql_view.cc:
  Now ST_SELECT_LEX::select_limit, offset_limit have type Item *
sql/sql_yacc.yy:
  Add grammar support for LIMIT ?, ? clause.
parent a9ccff55
......@@ -174,11 +174,8 @@ where a=2
limit 1';
execute stmt1 ;
select a,b from t1 where b = 'bla' ;
# currently (May 2004, Version 4.1) it is impossible
-- error 1064
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
--disable_query_log
select '------ insert tests ------' as test_sequence ;
......
......@@ -300,10 +300,8 @@ set @arg00=1;
prepare stmt1 from ' select a,b from t1 order by a
limit 1 ';
execute stmt1 ;
# currently (May 2004, Version 4.1) it is impossible
-- error 1064
prepare stmt1 from ' select a,b from t1
limit ? ';
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
##### parameter used in many places
set @arg00='b' ;
......
......@@ -634,3 +634,44 @@ id
3
deallocate prepare stmt;
drop table t1, t2;
create table t1 (a int);
insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
prepare stmt from "select * from t1 limit ?, ?";
set @offset=0, @limit=1;
execute stmt using @offset, @limit;
a
1
select * from t1 limit 0, 1;
a
1
set @offset=3, @limit=2;
execute stmt using @offset, @limit;
a
4
5
select * from t1 limit 3, 2;
a
4
5
prepare stmt from "select * from t1 limit ?";
execute stmt using @limit;
a
1
2
prepare stmt from "select * from t1 where a in (select a from t1 limit ?)";
ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
prepare stmt from "select * from t1 union all select * from t1 limit ?, ?";
set @offset=9;
set @limit=2;
execute stmt using @offset, @limit;
a
10
1
prepare stmt from "(select * from t1 limit ?, ?) union all
(select * from t1 limit ?, ?) order by a limit ?";
execute stmt using @offset, @limit, @offset, @limit, @limit;
a
10
10
drop table t1;
deallocate prepare stmt;
......@@ -444,9 +444,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -1381,10 +1382,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
......@@ -444,9 +444,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -1364,10 +1365,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
......@@ -445,9 +445,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -1365,10 +1366,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
......@@ -487,9 +487,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -1407,10 +1408,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......@@ -3500,9 +3499,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -4420,10 +4420,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
......@@ -444,9 +444,10 @@ limit 1 ';
execute stmt1 ;
a b
1 one
prepare stmt1 from ' select a,b from t1
limit ? ';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 2
prepare stmt1 from ' select a,b from t1 limit ? ';
execute stmt1 using @arg00;
a b
1 one
set @arg00='b' ;
set @arg01=0 ;
set @arg02=2 ;
......@@ -1364,10 +1365,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
use test;
drop table if exists t1, t9 ;
create table t1
use test; drop table if exists t1, t9 ; create table t1
(
a int, b varchar(30),
primary key(a)
......@@ -1364,10 +1362,8 @@ execute stmt1 ;
select a,b from t1 where b = 'bla' ;
a b
2 bla
prepare stmt1 from 'update t1 set b=''bla''
where a=2
limit ?';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 3
prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
execute stmt1 using @arg00;
test_sequence
------ insert tests ------
delete from t1 ;
......
......@@ -664,3 +664,32 @@ select t2.id from t2, t1 where (t1.id=1 and t2.t1_id=t1.id);
deallocate prepare stmt;
drop table t1, t2;
#
# Bug#7306 LIMIT ?, ? and also WL#1785 " Prepared statements: implement
# support for placeholders in LIMIT clause."
# Add basic test coverage for the feature.
#
create table t1 (a int);
insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
prepare stmt from "select * from t1 limit ?, ?";
set @offset=0, @limit=1;
execute stmt using @offset, @limit;
select * from t1 limit 0, 1;
set @offset=3, @limit=2;
execute stmt using @offset, @limit;
select * from t1 limit 3, 2;
prepare stmt from "select * from t1 limit ?";
execute stmt using @limit;
--error 1235
prepare stmt from "select * from t1 where a in (select a from t1 limit ?)";
prepare stmt from "select * from t1 union all select * from t1 limit ?, ?";
set @offset=9;
set @limit=2;
execute stmt using @offset, @limit;
prepare stmt from "(select * from t1 limit ?, ?) union all
(select * from t1 limit ?, ?) order by a limit ?";
execute stmt using @offset, @limit, @offset, @limit, @limit;
drop table t1;
deallocate prepare stmt;
......@@ -334,6 +334,11 @@ class Item {
If value is not null null_value flag will be reset to FALSE.
*/
virtual longlong val_int()=0;
/*
This is just a shortcut to avoid the cast. You should still use
unsigned_flag to check the sign of the item.
*/
inline ulonglong val_uint() { return (ulonglong) val_int(); }
/*
Return string representation of this item object.
......@@ -978,10 +983,10 @@ class Item_int :public Item_num
longlong value;
Item_int(int32 i,uint length=11) :value((longlong) i)
{ max_length=length; fixed= 1; }
#ifdef HAVE_LONG_LONG
Item_int(longlong i,uint length=21) :value(i)
{ max_length=length; fixed= 1; }
#endif
Item_int(ulonglong i, uint length= 21) :value((longlong)i)
{ max_length=length; fixed= 1; unsigned_flag= 1; }
Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; }
Item_int(const char *str_arg, uint length=64);
......@@ -1019,9 +1024,8 @@ class Item_uint :public Item_int
{
public:
Item_uint(const char *str_arg, uint length);
Item_uint(uint32 i) :Item_int((ulonglong) i, 10) {}
Item_uint(const char *str_arg, longlong i, uint length);
Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ unsigned_flag= 1; }
double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
......
......@@ -602,8 +602,8 @@ void Item_exists_subselect::fix_length_and_dec()
decimals= 0;
max_length= 1;
max_columns= engine->cols();
/* We need only 1 row to determinate existence */
unit->global_parameters->select_limit= 1;
/* We need only 1 row to determine existence */
unit->global_parameters->select_limit= new Item_int(1);
}
double Item_exists_subselect::val_real()
......
......@@ -320,7 +320,7 @@ sp_head::sp_head()
*sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
state= INITIALIZED;
state= INITIALIZED_FOR_SP;
m_backpatch.empty();
m_lex.empty();
hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
......@@ -1078,7 +1078,7 @@ sp_head::restore_thd_mem_root(THD *thd)
DBUG_ENTER("sp_head::restore_thd_mem_root");
Item *flist= free_list; // The old list
set_item_arena(thd); // Get new free_list and mem_root
state= INITIALIZED;
state= INITIALIZED_FOR_SP;
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
......
......@@ -665,8 +665,8 @@ class Item_arena
#endif
enum enum_state
{
INITIALIZED= 0, PREPARED= 1, EXECUTED= 3, CONVENTIONAL_EXECUTION= 2,
ERROR= -1
INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2,
CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1
};
enum_state state;
......@@ -695,6 +695,7 @@ class Item_arena
virtual Type type() const;
virtual ~Item_arena() {};
inline bool is_stmt_prepare() const { return state == INITIALIZED; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
......
......@@ -217,6 +217,8 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
queries defined. After temporary table is filled, if this is not EXPLAIN,
then the entire unit / node is deleted. unit is deleted if UNION is used
for derived table and node is deleted is it is a simple SELECT.
If you use this function, make sure it's not called at prepare.
Due to evaluation of LIMIT clause it can not be used at prepared stage.
RETURN
0 ok
......@@ -245,11 +247,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
}
else
{
unit->offset_limit_cnt= first_select->offset_limit;
unit->select_limit_cnt= first_select->select_limit+
first_select->offset_limit;
if (unit->select_limit_cnt < first_select->select_limit)
unit->select_limit_cnt= HA_POS_ERROR;
unit->set_limit(first_select);
if (unit->select_limit_cnt == HA_POS_ERROR)
first_select->options&= ~OPTION_FOUND_ROWS;
......
......@@ -225,20 +225,22 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
MYSQL_ERROR *err;
SELECT_LEX *sel= &thd->lex->select_lex;
ha_rows offset= sel->offset_limit, limit= sel->select_limit;
SELECT_LEX_UNIT *unit= &thd->lex->unit;
ha_rows idx= 0;
Protocol *protocol=thd->protocol;
unit->set_limit(sel);
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
while ((err= it++))
{
/* Skip levels that the user is not interested in */
if (!(levels_to_show & ((ulong) 1 << err->level)))
continue;
if (offset)
{
offset--;
if (++idx <= unit->offset_limit_cnt)
continue;
}
if (idx > unit->select_limit_cnt)
break;
protocol->prepare_for_resend();
protocol->store(warning_level_names[err->level],
warning_level_length[err->level], system_charset_info);
......@@ -246,8 +248,6 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
protocol->store(err->msg, strlen(err->msg), system_charset_info);
if (protocol->write())
DBUG_RETURN(TRUE);
if (!--limit)
break;
}
send_eof(thd);
DBUG_RETURN(FALSE);
......
......@@ -321,8 +321,8 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
key_expr
ha_rkey_mode
cond
select_limit
offset_limit
select_limit_cnt
offset_limit_cnt
RETURN
FALSE ok
......@@ -333,7 +333,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
enum enum_ha_read_modes mode, char *keyname,
List<Item> *key_expr,
enum ha_rkey_function ha_rkey_mode, Item *cond,
ha_rows select_limit,ha_rows offset_limit)
ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
{
TABLE_LIST *hash_tables;
TABLE *table;
......@@ -429,7 +429,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0))
goto err0;
select_limit+=offset_limit;
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
HANDLER_TABLES_HACK(thd);
......@@ -447,7 +446,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
table->file->init_table_handle_for_HANDLER();
for (num_rows=0; num_rows < select_limit; )
for (num_rows=0; num_rows < select_limit_cnt; )
{
switch (mode) {
case RFIRST:
......@@ -535,7 +534,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
if (cond && !cond->val_int())
continue;
if (num_rows >= offset_limit)
if (num_rows >= offset_limit_cnt)
{
Item *item;
protocol->prepare_for_resend();
......
......@@ -1138,8 +1138,9 @@ void st_select_lex::init_select()
order_list.elements= 0;
order_list.first= 0;
order_list.next= (byte**) &order_list.first;
select_limit= HA_POS_ERROR;
offset_limit= 0;
/* Set limit and offset to default values */
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
}
......@@ -1363,7 +1364,7 @@ ulong st_select_lex_node::get_table_join_options()
*/
bool st_select_lex::test_limit()
{
if (select_limit != HA_POS_ERROR)
if (select_limit != 0)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
......@@ -1551,24 +1552,20 @@ void st_select_lex::print_limit(THD *thd, String *str)
item->substype() == Item_subselect::IN_SUBS ||
item->substype() == Item_subselect::ALL_SUBS))
{
DBUG_ASSERT(!item->fixed || select_limit == 1L && offset_limit == 0L);
DBUG_ASSERT(!item->fixed ||
select_limit->val_int() == LL(1) && offset_limit == 0);
return;
}
if (explicit_limit)
{
str->append(" limit ", 7);
char buff[20];
// latin1 is good enough for numbers
String st(buff, sizeof(buff), &my_charset_latin1);
st.set((ulonglong)select_limit, &my_charset_latin1);
str->append(st);
if (offset_limit)
{
offset_limit->print(str);
str->append(',');
st.set((ulonglong)select_limit, &my_charset_latin1);
str->append(st);
}
select_limit->print(str);
}
}
......@@ -1619,7 +1616,7 @@ bool st_lex::can_be_merged()
select_lex.with_sum_func == 0 &&
select_lex.table_list.elements >= 1 &&
!(select_lex.options & SELECT_DISTINCT) &&
select_lex.select_limit == HA_POS_ERROR);
select_lex.select_limit == 0);
}
......@@ -1756,11 +1753,15 @@ bool st_lex::need_correct_ident()
values - SELECT_LEX with initial values for counters
*/
void st_select_lex_unit::set_limit(SELECT_LEX *values)
void st_select_lex_unit::set_limit(SELECT_LEX *sl)
{
offset_limit_cnt= values->offset_limit;
select_limit_cnt= values->select_limit+values->offset_limit;
if (select_limit_cnt < values->select_limit)
ulonglong select_limit_val;
select_limit_val= sl->select_limit ? sl->select_limit->val_uint() :
HA_POS_ERROR;
offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
select_limit_cnt= select_limit_val + offset_limit_cnt;
if (select_limit_cnt < select_limit_val)
select_limit_cnt= HA_POS_ERROR; // no limit
}
......
......@@ -488,7 +488,7 @@ class st_select_lex: public st_select_lex_node
List<List_item> expr_list;
List<List_item> when_list; /* WHEN clause (expression) */
SQL_LIST *gorder_list;
ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
Item **ref_pointer_array;
......
......@@ -2351,7 +2351,8 @@ mysql_execute_command(THD *thd)
{
SELECT_LEX *param= lex->unit.global_parameters;
if (!param->explicit_limit)
param->select_limit= thd->variables.select_limit;
param->select_limit=
new Item_int((ulonglong)thd->variables.select_limit);
}
select_result *result=lex->result;
......@@ -3146,13 +3147,15 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
res= (result= mysql_update(thd, all_tables,
select_lex->item_list,
lex->value_list,
select_lex->where,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
select_lex->select_limit,
unit->select_limit_cnt,
lex->duplicates, lex->ignore));
/* mysql_update return 2 if we need to switch to multi-update */
if (result != 2)
......@@ -3258,9 +3261,11 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= delete_precheck(thd, all_tables)))
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
select_lex->select_limit, select_lex->options);
unit->select_limit_cnt, select_lex->options);
break;
}
case SQLCOM_DELETE_MULTI:
......@@ -3847,9 +3852,10 @@ mysql_execute_command(THD *thd)
*/
if (check_db_used(thd, all_tables))
goto error;
unit->set_limit(select_lex);
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
select_lex->select_limit, select_lex->offset_limit);
unit->select_limit_cnt, unit->offset_limit_cnt);
break;
case SQLCOM_BEGIN:
......@@ -5130,7 +5136,6 @@ mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
select_lex->select_limit= HA_POS_ERROR;
lex->orig_sql_command= SQLCOM_END;
lex->wild= 0;
if (select_lex == &lex->select_lex)
......@@ -5145,6 +5150,7 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
THD *thd;
DBUG_ENTER("mysql_new_select");
if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
......@@ -5194,7 +5200,7 @@ mysql_new_select(LEX *lex, bool move_down)
fake->select_number= INT_MAX;
fake->make_empty_select();
fake->linkage= GLOBAL_OPTIONS_TYPE;
fake->select_limit= HA_POS_ERROR;
fake->select_limit= 0;
}
}
......@@ -5242,8 +5248,8 @@ void mysql_init_multi_delete(LEX *lex)
{
lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
lex->select_lex.select_limit= lex->unit.select_limit_cnt=
HA_POS_ERROR;
lex->select_lex.select_limit= 0;
lex->unit.select_limit_cnt= HA_POS_ERROR;
lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
lex->query_tables= 0;
......@@ -6757,8 +6763,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (select_lex->order_list.elements)
msg= "ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR)
else if (select_lex->select_limit)
msg= "LIMIT";
if (msg)
{
......
......@@ -1316,6 +1316,7 @@ bool mysql_show_binlog_events(THD* thd)
if (mysql_bin_log.is_open())
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
SELECT_LEX_UNIT *unit= &thd->lex->unit;
ha_rows event_count, limit_start, limit_end;
my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
......@@ -1324,8 +1325,9 @@ bool mysql_show_binlog_events(THD* thd)
LOG_INFO linfo;
Log_event* ev;
limit_start= thd->lex->current_select->offset_limit;
limit_end= thd->lex->current_select->select_limit + limit_start;
unit->set_limit(thd->lex->current_select);
limit_start= unit->offset_limit_cnt;
limit_end= unit->select_limit_cnt;
name= search_file_name;
if (log_file_name)
......
......@@ -10051,7 +10051,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
join->do_send_rows= 0;
if (join->unit->fake_select_lex)
join->unit->fake_select_lex->select_limit= HA_POS_ERROR;
join->unit->fake_select_lex->select_limit= 0;
DBUG_RETURN(NESTED_LOOP_OK);
}
}
......
......@@ -448,7 +448,7 @@ bool st_select_lex_unit::exec()
table->no_keyread=1;
}
res= sl->join->error;
offset_limit_cnt= sl->offset_limit;
offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : 0;
if (!res)
{
examined_rows+= thd->examined_row_count;
......
......@@ -1000,8 +1000,9 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
we do not support updatable UNIONs in VIEW, so we can check just limit of
LEX::select_lex
*/
if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT ||
thd->lex->select_lex.select_limit == HA_POS_ERROR)
if ((!view->view && !view->belong_to_view) ||
thd->lex->sql_command == SQLCOM_INSERT ||
thd->lex->select_lex.select_limit == 0)
DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
table= view->table;
if (view->belong_to_view)
......
......@@ -721,7 +721,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
signed_literal now_or_signed_literal opt_escape
sp_opt_default
simple_ident_nospvar simple_ident_q
field_or_var
field_or_var limit_option
%type <item_num>
NUM_literal
......@@ -5542,8 +5542,8 @@ opt_limit_clause_init:
{
LEX *lex= Lex;
SELECT_LEX *sel= lex->current_select;
sel->offset_limit= 0L;
sel->select_limit= HA_POS_ERROR;
sel->offset_limit= 0;
sel->select_limit= 0;
}
| limit_clause {}
;
......@@ -5558,21 +5558,21 @@ limit_clause:
;
limit_options:
ulong_num
limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
sel->offset_limit= 0L;
sel->offset_limit= 0;
sel->explicit_limit= 1;
}
| ulong_num ',' ulong_num
| limit_option ',' limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $3;
sel->offset_limit= $1;
sel->explicit_limit= 1;
}
| ulong_num OFFSET_SYM ulong_num
| limit_option OFFSET_SYM limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
......@@ -5580,18 +5580,23 @@ limit_options:
sel->explicit_limit= 1;
}
;
limit_option:
param_marker
| ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
| LONG_NUM { $$= new Item_uint($1.str, $1.length); }
| NUM { $$= new Item_uint($1.str, $1.length); }
delete_limit_clause:
/* empty */
{
LEX *lex=Lex;
lex->current_select->select_limit= HA_POS_ERROR;
lex->current_select->select_limit= 0;
}
| LIMIT ulonglong_num
| LIMIT limit_option
{
SELECT_LEX *sel= Select;
sel->select_limit= (ha_rows) $2;
sel->select_limit= $2;
sel->explicit_limit= 1;
};
......@@ -7942,8 +7947,8 @@ handler:
LEX *lex=Lex;
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
lex->current_select->select_limit= 1;
lex->current_select->offset_limit= 0L;
lex->current_select->select_limit= new Item_int(1);
lex->current_select->offset_limit= 0;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment