diff options
author | unknown <konstantin@mysql.com> | 2005-06-07 14:11:36 +0400 |
---|---|---|
committer | unknown <konstantin@mysql.com> | 2005-06-07 14:11:36 +0400 |
commit | 5188f031ae9b8b7eca9092b82d454a567154737a (patch) | |
tree | d2686d80a3486e1912b96a6e6774bd3f77da0022 /sql | |
parent | a9ccff554a9c6ae44a833e156e0010cba6e3362d (diff) | |
download | mariadb-git-5188f031ae9b8b7eca9092b82d454a567154737a.tar.gz |
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.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.h | 12 | ||||
-rw-r--r-- | sql/item_subselect.cc | 4 | ||||
-rw-r--r-- | sql/sp_head.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 5 | ||||
-rw-r--r-- | sql/sql_derived.cc | 8 | ||||
-rw-r--r-- | sql/sql_error.cc | 16 | ||||
-rw-r--r-- | sql/sql_handler.cc | 11 | ||||
-rw-r--r-- | sql/sql_lex.cc | 33 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 25 | ||||
-rw-r--r-- | sql/sql_repl.cc | 6 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 2 | ||||
-rw-r--r-- | sql/sql_view.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 29 |
15 files changed, 90 insertions, 74 deletions
diff --git a/sql/item.h b/sql/item.h index 4f5ed9934c5..4a7dd5b6390 100644 --- a/sql/item.h +++ b/sql/item.h @@ -335,6 +335,11 @@ public: */ 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. SYNOPSIS @@ -978,10 +983,10 @@ public: 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*); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 4f1e5b9a290..7b83cbcd53a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -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() diff --git a/sql/sp_head.cc b/sql/sp_head.cc index c17c8b81cb2..a72128a54da 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -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)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7c8ead7558e..a976407322f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -665,8 +665,8 @@ public: #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 @@ public: 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; } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 2ae293c1bff..e1d701936cf 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -217,6 +217,8 @@ exit: 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; diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 3bda16202b9..8a12339ccee 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -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); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 1aa034ce61c..aca53db0ec8 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -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(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 574c9966c63..6b9330182d6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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 } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e297d303f3d..5022392565c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -488,7 +488,7 @@ public: 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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a9e68de3705..1a3a03012eb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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 @@ unsent_create_error: 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 @@ unsent_create_error: 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 @@ unsent_create_error: */ 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) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 71cebb61ae6..0b5ac63dd0b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -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) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 27ef3fcea6f..d07dd523f75 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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); } } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 56401ced67c..912636b6cf3 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -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; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 289bf9d28a3..9f0c3260d8f 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -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) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2f584bc6b4e..47a2b098538 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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; } |