diff options
author | unknown <pem@mysql.telia.com> | 2003-10-10 16:57:21 +0200 |
---|---|---|
committer | unknown <pem@mysql.telia.com> | 2003-10-10 16:57:21 +0200 |
commit | 04c6b9b8d8c10fd83ab80f1a3e2d6bd58b34b825 (patch) | |
tree | 502f5a108855c24da25af7d42aa635d0a3c5103b /sql | |
parent | 4379cbcf3056a33f41ddf489828203a6c03e793f (diff) | |
download | mariadb-git-04c6b9b8d8c10fd83ab80f1a3e2d6bd58b34b825.tar.gz |
WL#962: Added simple, read-only, non-scrolling, asensitive cursors in SPs, using the
(updated) Protocol_cursor class.
Also did some bug fixes.
Docs/sp-imp-spec.txt:
Added CURSOR docs (and fixed typos)
Docs/sp-implemented.txt:
Updated for CURSORs
include/mysqld_error.h:
New error codes/messages for CURSORs
libmysqld/Makefile.am:
SP cursors now needs this.
mysql-test/r/sp-error.result:
New tests for cursors.
mysql-test/r/sp.result:
New tests for cursors.
mysql-test/t/sp-error.test:
New tests for cursors.
mysql-test/t/sp.test:
New tests for cursors.
sql/protocol.cc:
We now always have Protocol_cursor (SPs use it)
sql/protocol.h:
Fixed bugs in Protocol_cursor (for SPs)
sql/protocol_cursor.cc:
Fixed bugs in Protocol_cursor (for SPs)
sql/share/czech/errmsg.txt:
New error codes/messages for CURSORs
sql/share/danish/errmsg.txt:
New error codes/messages for CURSORs
sql/share/dutch/errmsg.txt:
New error codes/messages for CURSORs
sql/share/english/errmsg.txt:
New error codes/messages for CURSORs
sql/share/estonian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/french/errmsg.txt:
New error codes/messages for CURSORs
sql/share/german/errmsg.txt:
New error codes/messages for CURSORs
sql/share/greek/errmsg.txt:
New error codes/messages for CURSORs
sql/share/hungarian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/italian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/japanese/errmsg.txt:
New error codes/messages for CURSORs
sql/share/korean/errmsg.txt:
New error codes/messages for CURSORs
sql/share/norwegian-ny/errmsg.txt:
New error codes/messages for CURSORs
sql/share/norwegian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/polish/errmsg.txt:
New error codes/messages for CURSORs
sql/share/portuguese/errmsg.txt:
New error codes/messages for CURSORs
sql/share/romanian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/russian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/serbian/errmsg.txt:
New error codes/messages for CURSORs
sql/share/slovak/errmsg.txt:
New error codes/messages for CURSORs
sql/share/spanish/errmsg.txt:
New error codes/messages for CURSORs
sql/share/swedish/errmsg.txt:
New error codes/messages for CURSORs
sql/share/ukrainian/errmsg.txt:
New error codes/messages for CURSORs
sql/sp_head.cc:
Added cursor support.
Also fixed problems with item_lists, where pointers and ref_pointer_arrays.
sql/sp_head.h:
Added cursor support
sql/sp_pcontext.cc:
Added cursor support
sql/sp_pcontext.h:
Added cursor support
sql/sp_rcontext.cc:
Added cursor support, in particular the new sp_cursor class.
sql/sp_rcontext.h:
Added cursor support, in particular the new sp_cursor class.
sql/sql_lex.h:
We sometimes need to copy item_lists in LEX when executing substatements in SPs
sql/sql_yacc.yy:
Added minimal cursor support (not the full syntax yet).
Diffstat (limited to 'sql')
34 files changed, 885 insertions, 61 deletions
diff --git a/sql/protocol.cc b/sql/protocol.cc index 35a299e37bf..2ad12e56ff7 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1145,12 +1145,3 @@ bool Protocol_prep::store_time(TIME *tm) buff[0]=(char) length; // Length is stored first return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); } - -#ifdef EMBEDDED_LIBRARY -/* Should be removed when we define the Protocol_cursor's future */ -bool Protocol_cursor::write() -{ - return Protocol_simple::write(); -} -#endif - diff --git a/sql/protocol.h b/sql/protocol.h index 94fd303e259..6aa9b6414ae 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -47,17 +47,13 @@ public: Protocol(THD *thd) { init(thd); } virtual ~Protocol() {} void init(THD* thd); - bool send_fields(List<Item> *list, uint flag); + virtual bool send_fields(List<Item> *list, uint flag); bool send_records_num(List<Item> *list, ulonglong records); bool store(I_List<i_string> *str_list); bool store(const char *from, CHARSET_INFO *cs); String *storage_packet() { return packet; } inline void free() { packet->free(); } -#ifndef EMBEDDED_LIBRARY - bool write(); -#else virtual bool write(); -#endif inline bool store(uint32 from) { return store_long((longlong) from); } inline bool store(longlong from) @@ -158,6 +154,7 @@ public: Protocol_cursor(THD *thd, MEM_ROOT *ini_alloc) :Protocol_simple(thd), alloc(ini_alloc) {} bool prepare_for_send(List<Item> *item_list) { + row_count= 0; fields= NULL; data= NULL; prev_record= &data; @@ -165,6 +162,7 @@ public: } bool send_fields(List<Item> *list, uint flag); bool write(); + uint get_field_count() { return field_count; } }; void send_warning(THD *thd, uint sql_errno, const char *err=0); diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc index 19e3bb06d74..abb391fbd67 100644 --- a/sql/protocol_cursor.cc +++ b/sql/protocol_cursor.cc @@ -51,6 +51,7 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag) client_field->name= strdup_root(alloc, server_field.col_name); client_field->org_table= strdup_root(alloc, server_field.org_table_name); client_field->org_name= strdup_root(alloc, server_field.org_col_name); + client_field->catalog= strdup_root(alloc, ""); client_field->length= server_field.length; client_field->type= server_field.type; client_field->flags= server_field.flags; @@ -60,6 +61,7 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag) client_field->name_length= strlen(client_field->name); client_field->org_name_length= strlen(client_field->org_name); client_field->org_table_length= strlen(client_field->org_table); + client_field->catalog_length= 0; client_field->charsetnr= server_field.charsetnr; if (INTERNAL_NUM_FIELD(client_field)) @@ -100,17 +102,17 @@ bool Protocol_cursor::write() byte *to; new_record= (MYSQL_ROWS *)alloc_root(alloc, - sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length()); + sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length()); if (!new_record) goto err; data= (byte **)(new_record + 1); new_record->data= (char **)data; - to= (byte *)(fields + field_count + 1); + to= (byte *)data + (field_count + 1)*sizeof(char *); for (; cur_field < fields_end; ++cur_field, ++data) { - if ((len=net_field_length((uchar **)&cp))) + if ((len= net_field_length((uchar **)&cp)) == 0) { *data= 0; } @@ -121,6 +123,7 @@ bool Protocol_cursor::write() // TODO error signal send_error(thd, CR_MALFORMED_PACKET); return TRUE; } + *data= to; memcpy(to,(char*) cp,len); to[len]=0; to+=len+1; @@ -129,6 +132,7 @@ bool Protocol_cursor::write() cur_field->max_length=len; } } + *data= 0; *prev_record= new_record; prev_record= &new_record->next; @@ -139,5 +143,3 @@ bool Protocol_cursor::write() // TODO error signal send_error(thd, ER_OUT_OF_RESOURCES); return TRUE; } - - diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index d572b3e4b29..b21a65342aa 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -310,3 +310,11 @@ character-set=latin2 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index c83c6ce000e..7b2c114d456 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -304,3 +304,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 7001dc859b9..13b2802b8ba 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -312,3 +312,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 3936957fad8..3e58da13cf2 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -301,3 +301,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 7d85d53b9ce..3a30c65cd58 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -306,3 +306,11 @@ character-set=latin7 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index a3dcdea06c0..40edf256b57 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -301,3 +301,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 59735b8bb5d..66df9eb519d 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -310,3 +310,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index bcfd619a0a1..4777d09df46 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -301,3 +301,11 @@ character-set=greek "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index c4a4cdb1fb6..b3aeb507016 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -303,3 +303,11 @@ character-set=latin2 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 3e1034c8c4a..5b83f699791 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -301,3 +301,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index eb2e456fa66..5916c5f8a32 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -303,3 +303,11 @@ character-set=ujis "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 82f55bb7b02..154ed0d9b6f 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -301,3 +301,11 @@ character-set=euckr "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 74b5fbfbb65..4ff587bcee1 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -303,3 +303,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index ac08124cf26..b8a47078bcc 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -303,3 +303,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 86dd51da336..546d24adc9f 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -305,3 +305,11 @@ character-set=latin2 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 6e55a8c071e..69d573b53af 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -302,3 +302,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 50521fbef94..af7b26c9ef1 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -305,3 +305,11 @@ character-set=latin2 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index f4ef5415136..435c9c5193a 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -303,3 +303,11 @@ character-set=koi8r "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 83adc33c73b..2c7dc25e0ac 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -296,3 +296,11 @@ character-set=cp1250 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index fc4cb769bc8..3596b73682b 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -309,3 +309,11 @@ character-set=latin2 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 129df358d2e..d24153d29d2 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -303,3 +303,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index e17e20aa5f5..3931ce9718e 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -301,3 +301,11 @@ character-set=latin1 "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index cb29db0330e..0f69481aefe 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -306,3 +306,11 @@ character-set=koi8u "Undefined CONDITION: %s" "No RETURN found in FUNCTION %s" "FUNCTION %s ended without RETURN" +"Cursor statement must be a SELECT" +"Cursor SELECT must not have INTO" +"Undefined CURSOR: %s" +"Cursor is already open" +"Cursor is not open" +"Undeclared variable: %s" +"Wrong number of FETCH variables" +"No data to FETCH" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 82afb9305f0..bea4d7a34be 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -289,6 +289,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) uint csize = m_pcont->max_framesize(); uint params = m_pcont->params(); uint hmax = m_pcont->handlers(); + uint cmax = m_pcont->cursors(); sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; uint i; @@ -304,7 +305,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } // QQ Should have some error checking here? (types, etc...) - nctx= new sp_rcontext(csize, hmax); + nctx= new sp_rcontext(csize, hmax, cmax); for (i= 0 ; i < params && i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -335,6 +336,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } } + nctx->pop_all_cursors(); // To avoid memory leaks after an error thd->spcont= octx; DBUG_RETURN(ret); } @@ -349,6 +351,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) uint csize = m_pcont->max_framesize(); uint params = m_pcont->params(); uint hmax = m_pcont->handlers(); + uint cmax = m_pcont->cursors(); sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx @@ -360,17 +363,17 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) DBUG_RETURN(-1); } - if (csize > 0 || hmax > 0) + if (csize > 0 || hmax > 0 || cmax > 0) { uint i; List_iterator_fast<Item> li(*args); Item *it; - nctx = new sp_rcontext(csize, hmax); + nctx= new sp_rcontext(csize, hmax, cmax); if (! octx) { // Create a temporary old context - octx = new sp_rcontext(csize, hmax); - tmp_octx = TRUE; + octx= new sp_rcontext(csize, hmax, cmax); + tmp_octx= TRUE; } // QQ: Should do type checking? for (i = 0 ; (it= li++) && i < params ; i++) @@ -443,13 +446,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } } } - - if (tmp_octx) - thd->spcont= NULL; - else - thd->spcont= octx; } + if (tmp_octx) + octx= NULL; + if (nctx) + nctx->pop_all_cursors(); // To avoid memory leaks after an error + thd->spcont= octx; + DBUG_RETURN(ret); } @@ -596,12 +600,20 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex->sql_command)); + int res= exec_stmt(thd, m_lex); + *nextp = m_ip+1; + DBUG_RETURN(res); +} + +int +sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) +{ LEX *olex; // The other lex Item *freelist; int res; olex= thd->lex; // Save the other lex - thd->lex= m_lex; // Use my own lex + thd->lex= lex; // Use my own lex thd->lex->thd = thd; // QQ Not reentrant! thd->lex->unit.thd= thd; // QQ Not reentrant freelist= thd->free_list; @@ -610,10 +622,19 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) // Copy WHERE clause pointers to avoid damaging by optimisation // Also clear ref_pointer_arrays. - for (SELECT_LEX *sl= m_lex->all_selects_list ; + for (SELECT_LEX *sl= lex->all_selects_list ; sl ; sl= sl->next_select_in_list()) { + List_iterator_fast<Item> li(sl->item_list); + + if (sl->with_wild) + { + // Copy item_list + sl->item_list_copy.empty(); + while (Item *it= li++) + sl->item_list_copy.push_back(it); + } sl->ref_pointer_array= 0; if (sl->prep_where) sl->where= sl->prep_where->copy_andor_structure(thd); @@ -628,11 +649,22 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) close_thread_tables(thd); /* Free tables */ } + for (SELECT_LEX *sl= lex->all_selects_list ; + sl ; + sl= sl->next_select_in_list()) + { + if (sl->with_wild) + { + // Restore item_list + sl->item_list.empty(); + while (Item *it= sl->item_list_copy.pop()) + sl->item_list.push_back(it); + } + } thd->lex= olex; // Restore the other lex thd->free_list= freelist; - *nextp = m_ip+1; - DBUG_RETURN(res); + return res; } // @@ -747,3 +779,96 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) *nextp= thd->spcont->pop_hstack(); DBUG_RETURN(0); } + +// +// sp_instr_cpush +// +int +sp_instr_cpush::execute(THD *thd, uint *nextp) +{ + DBUG_ENTER("sp_instr_cpush::execute"); + thd->spcont->push_cursor(m_lex); + *nextp= m_ip+1; + DBUG_RETURN(0); +} + +sp_instr_cpush::~sp_instr_cpush() +{ + if (m_lex) + delete m_lex; +} + +// +// sp_instr_cpop +// +int +sp_instr_cpop::execute(THD *thd, uint *nextp) +{ + DBUG_ENTER("sp_instr_cpop::execute"); + thd->spcont->pop_cursors(m_count); + *nextp= m_ip+1; + DBUG_RETURN(0); +} + +// +// sp_instr_copen +// +int +sp_instr_copen::execute(THD *thd, uint *nextp) +{ + sp_cursor *c= thd->spcont->get_cursor(m_cursor); + int res; + DBUG_ENTER("sp_instr_copen::execute"); + + if (! c) + res= -1; + else + { + LEX *lex= c->pre_open(thd); + + if (! lex) + res= -1; + else + res= exec_stmt(thd, lex); + c->post_open(thd, (res == 0 ? TRUE : FALSE)); + } + + *nextp= m_ip+1; + DBUG_RETURN(res); +} + +// +// sp_instr_cclose +// +int +sp_instr_cclose::execute(THD *thd, uint *nextp) +{ + sp_cursor *c= thd->spcont->get_cursor(m_cursor); + int res; + DBUG_ENTER("sp_instr_cclose::execute"); + + if (! c) + res= -1; + else + res= c->close(thd); + *nextp= m_ip+1; + DBUG_RETURN(res); +} + +// +// sp_instr_cfetch +// +int +sp_instr_cfetch::execute(THD *thd, uint *nextp) +{ + sp_cursor *c= thd->spcont->get_cursor(m_cursor); + int res; + DBUG_ENTER("sp_instr_cfetch::execute"); + + if (! c) + res= -1; + else + res= c->fetch(thd, &m_varlist); + *nextp= m_ip+1; + DBUG_RETURN(res); +} diff --git a/sql/sp_head.h b/sql/sp_head.h index a68a1bf83ef..b582d37a185 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -33,10 +33,9 @@ Item_result sp_map_result_type(enum enum_field_types type); struct sp_label; - class sp_instr; - struct sp_cond_type; +struct sp_pvar; class sp_head : public Sql_alloc { @@ -278,6 +277,10 @@ public: return m_lex; } +protected: + + int exec_stmt(THD *thd, LEX *lex); // Execute a statement + private: LEX *m_lex; // My own lex @@ -503,4 +506,126 @@ private: }; // class sp_instr_hreturn : public sp_instr +class sp_instr_cpush : public sp_instr +{ + sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */ + void operator=(sp_instr_cpush &); + +public: + + sp_instr_cpush(uint ip, LEX *lex) + : sp_instr(ip), m_lex(lex) + {} + + virtual ~sp_instr_cpush(); + + virtual int execute(THD *thd, uint *nextp); + +private: + + LEX *m_lex; + +}; // class sp_instr_cpush : public sp_instr + + +class sp_instr_cpop : public sp_instr +{ + sp_instr_cpop(const sp_instr_cpop &); /* Prevent use of these */ + void operator=(sp_instr_cpop &); + +public: + + sp_instr_cpop(uint ip, uint count) + : sp_instr(ip), m_count(count) + {} + + virtual ~sp_instr_cpop() + {} + + virtual int execute(THD *thd, uint *nextp); + +private: + + uint m_count; + +}; // class sp_instr_cpop : public sp_instr + + +class sp_instr_copen : public sp_instr_stmt +{ + sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */ + void operator=(sp_instr_copen &); + +public: + + sp_instr_copen(uint ip, uint c) + : sp_instr_stmt(ip), m_cursor(c) + {} + + virtual ~sp_instr_copen() + {} + + virtual int execute(THD *thd, uint *nextp); + +private: + + uint m_cursor; // Stack index + +}; // class sp_instr_copen : public sp_instr_stmt + + +class sp_instr_cclose : public sp_instr +{ + sp_instr_cclose(const sp_instr_cclose &); /* Prevent use of these */ + void operator=(sp_instr_cclose &); + +public: + + sp_instr_cclose(uint ip, uint c) + : sp_instr(ip), m_cursor(c) + {} + + virtual ~sp_instr_cclose() + {} + + virtual int execute(THD *thd, uint *nextp); + +private: + + uint m_cursor; + +}; // class sp_instr_cclose : public sp_instr + + +class sp_instr_cfetch : public sp_instr +{ + sp_instr_cfetch(const sp_instr_cfetch &); /* Prevent use of these */ + void operator=(sp_instr_cfetch &); + +public: + + sp_instr_cfetch(uint ip, uint c) + : sp_instr(ip), m_cursor(c) + { + m_varlist.empty(); + } + + virtual ~sp_instr_cfetch() + {} + + virtual int execute(THD *thd, uint *nextp); + + void add_to_varlist(struct sp_pvar *var) + { + m_varlist.push_back(var); + } + +private: + + uint m_cursor; + List<struct sp_pvar> m_varlist; + +}; // class sp_instr_cfetch : public sp_instr + + #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index a192d78b9a3..3730230d47d 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -27,10 +27,11 @@ #include "sp_head.h" sp_pcontext::sp_pcontext() - : Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_genlab(0) + : Sql_alloc(), m_params(0), m_framesize(0), m_handlers(0), m_cursmax(0) { VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8)); m_label.empty(); } @@ -39,6 +40,7 @@ sp_pcontext::destroy() { delete_dynamic(&m_pvar); delete_dynamic(&m_cond); + delete_dynamic(&m_cursor); m_label.empty(); } @@ -124,8 +126,6 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val) if (p) { - if (m_cond.elements == m_framesize) - m_framesize += 1; p->name.str= name->str; p->name.length= name->length; p->val= val; @@ -155,3 +155,39 @@ sp_pcontext::find_cond(LEX_STRING *name) } return NULL; } + +void +sp_pcontext::push_cursor(LEX_STRING *name) +{ + LEX_STRING n; + + n.str= name->str; + n.length= name->length; + insert_dynamic(&m_cursor, (gptr)&n); + if (m_cursor.elements > m_cursmax) + m_cursmax= m_cursor.elements; +} + +/* + * See comment for find_pvar() above + */ +my_bool +sp_pcontext::find_cursor(LEX_STRING *name, uint *poff) +{ + uint i = m_cursor.elements; + + while (i-- > 0) + { + LEX_STRING n; + + get_dynamic(&m_cursor, (gptr)&n, i); + if (my_strnncoll(system_charset_info, + (const uchar *)name->str, name->length, + (const uchar *)n.str, n.length) == 0) + { + *poff= i; + return TRUE; + } + } + return FALSE; +} diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 6fb56faccf6..23be38edcbf 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -29,7 +29,7 @@ typedef enum sp_param_inout } sp_param_mode_t; -typedef struct +typedef struct sp_pvar { LEX_STRING name; enum enum_field_types type; @@ -200,17 +200,41 @@ class sp_pcontext : public Sql_alloc return m_handlers; } + // + // Cursors + // + + void + push_cursor(LEX_STRING *name); + + my_bool + find_cursor(LEX_STRING *name, uint *poff); + + inline void + pop_cursor(uint num) + { + while (num--) + pop_dynamic(&m_cursor); + } + + inline uint + cursors() + { + return m_cursmax; + } + private: uint m_params; // The number of parameters uint m_framesize; // The maximum framesize uint m_handlers; // The total number of handlers + uint m_cursmax; // The maximum number of cursors DYNAMIC_ARRAY m_pvar; // Parameters/variables DYNAMIC_ARRAY m_cond; // Conditions + DYNAMIC_ARRAY m_cursor; // Cursors List<sp_label_t> m_label; // The label list - uint m_genlab; // Gen. label counter }; // class sp_pcontext : public Sql_alloc diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 79d02d843ea..d73f3ed6dd7 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -23,16 +23,20 @@ #endif #include "mysql_priv.h" +#include "mysql.h" +#include "sp_head.h" #include "sp_rcontext.h" #include "sp_pcontext.h" -sp_rcontext::sp_rcontext(uint fsize, uint hmax) - : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0) +sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) + : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0), + m_hfound(-1), m_ccount(0) { m_frame= (Item **)sql_alloc(fsize * sizeof(Item*)); m_outs= (int *)sql_alloc(fsize * sizeof(int)); m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t)); m_hstack= (uint *)sql_alloc(hmax * sizeof(uint)); + m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *)); m_saved.empty(); } @@ -93,3 +97,141 @@ sp_rcontext::restore_variables(uint fp) while (i-- > fp) m_frame[i]= m_saved.pop(); } + +void +sp_rcontext::push_cursor(LEX *lex) +{ + m_cstack[m_ccount++]= new sp_cursor(lex); +} + +void +sp_rcontext::pop_cursors(uint count) +{ + while (count--) + { + delete m_cstack[--m_ccount]; + } +} + + +/* + * + * sp_cursor + * + */ + +// We have split this in two to make it easy for sp_instr_copen +// to reuse the sp_instr::exec_stmt() code. +LEX * +sp_cursor::pre_open(THD *thd) +{ + int res; + + if (m_isopen) + { + send_error(thd, ER_SP_CURSOR_ALREADY_OPEN); + return NULL; + } + + bzero((char *)&m_mem_root, sizeof(m_mem_root)); + init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); + if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL) + return NULL; + + m_oprot= thd->protocol; // Save the original protocol + thd->protocol= m_prot; + + m_ovio= thd->net.vio; // Prevent send_eof() + thd->net.vio= 0; + return m_lex; +} + +void +sp_cursor::post_open(THD *thd, my_bool isopen) +{ + thd->net.vio= m_ovio; // Restore the originals + thd->protocol= m_oprot; + m_isopen= isopen; + m_current_row= m_prot->data; +} + +int +sp_cursor::close(THD *thd) +{ + if (! m_isopen) + { + send_error(thd, ER_SP_CURSOR_NOT_OPEN); + return -1; + } + destroy(); + return 0; +} + +void +sp_cursor::destroy() +{ + delete m_prot; + m_prot= NULL; + free_root(&m_mem_root, MYF(0)); + bzero((char *)&m_mem_root, sizeof(m_mem_root)); + m_isopen= FALSE; +} + +int +sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) +{ + List_iterator_fast<struct sp_pvar> li(*vars); + sp_pvar_t *pv; + MYSQL_ROW row; + uint fldcount; + MYSQL_FIELD *fields= m_prot->fields; + + if (! m_isopen) + { + send_error(thd, ER_SP_CURSOR_NOT_OPEN); + return -1; + } + + if (m_current_row == NULL) + { + send_error(thd, ER_SP_FETCH_NO_DATA); + return -1; + } + + row= m_current_row->data; + for (fldcount= 0 ; (pv= li++) ; fldcount++) + { + Item *it; + const char *s; + + if (fldcount >= m_prot->get_field_count()) + { + send_error(thd, ER_SP_WRONG_NO_OF_FETCH_ARGS); + return -1; + } + s= row[fldcount]; + switch (sp_map_result_type(pv->type)) + { + case INT_RESULT: + it= new Item_int(s); + break; + case REAL_RESULT: + it= new Item_real(s, strlen(s)); + break; + default: + { + uint len= strlen(s); + it= new Item_string(thd->strmake(s, len), len, thd->db_charset); + break; + } + } + thd->spcont->set_item(pv->offset, it); + } + if (fldcount < m_prot->get_field_count()) + { + send_error(thd, ER_SP_WRONG_NO_OF_FETCH_ARGS); + return -1; + } + m_current_row= m_current_row->next; + return 0; +} diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index fe954ed0d94..027f2f74789 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -23,6 +23,8 @@ #endif struct sp_cond_type; +struct sp_cursor; +struct sp_pvar; #define SP_HANDLER_NONE 0 #define SP_HANDLER_EXIT 1 @@ -44,7 +46,7 @@ class sp_rcontext : public Sql_alloc public: - sp_rcontext(uint fsize, uint hmax); + sp_rcontext(uint fsize, uint hmax, uint cmax); ~sp_rcontext() { @@ -155,22 +157,93 @@ class sp_rcontext : public Sql_alloc void restore_variables(uint fp); + void + push_cursor(LEX *lex); + + void + pop_cursors(uint count); + + void + pop_all_cursors() + { + pop_cursors(m_ccount); + } + + inline sp_cursor * + get_cursor(uint i) + { + return m_cstack[i]; + } + private: uint m_count; uint m_fsize; Item **m_frame; int *m_outs; + Item *m_result; // For FUNCTIONs + sp_handler_t *m_handler; uint m_hcount; uint *m_hstack; uint m_hsp; - int m_hfound; // Set by find_handler; -1 if not found - List<Item> m_saved; // Saved variables + sp_cursor **m_cstack; + uint m_ccount; + }; // class sp_rcontext : public Sql_alloc + +class sp_cursor : public Sql_alloc +{ +public: + + sp_cursor(LEX *lex) + : m_lex(lex), m_isopen(0), m_current_row(NULL) + { + /* Empty */ + } + + virtual ~sp_cursor() + { + destroy(); + } + + // We have split this in two to make it easy for sp_instr_copen + // to reuse the sp_instr::exec_stmt() code. + LEX * + pre_open(THD *thd); + void + post_open(THD *thd, my_bool isopen); + + int + close(THD *thd); + + inline my_bool + is_open() + { + return m_isopen; + } + + int + fetch(THD *, List<struct sp_pvar> *vars); + +private: + + MEM_ROOT m_mem_root; // My own mem_root + LEX *m_lex; + Protocol_cursor *m_prot; + my_bool m_isopen; + Vio *m_ovio; // Original vio + Protocol *m_oprot; // Original protcol + MYSQL_ROWS *m_current_row; + + void + destroy(); + +}; // class sp_cursor : public Sql_alloc + #endif /* _SP_RCONTEXT_H_ */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 99a58f5fbf9..c836ff1ba38 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -348,6 +348,7 @@ public: enum olap_type olap; SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ List<Item> item_list; /* list of fields & expressions */ + List<Item> item_list_copy; /* For SPs */ List<String> interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c9fb5e0db41..58c1680a5f3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -86,7 +86,8 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) st_select_lex *select_lex; chooser_compare_func_creator boolfunc2creator; struct sp_cond_type *spcondtype; - struct { int vars, conds, hndlrs; } spblock; + struct { int vars, conds, hndlrs, curs; } spblock; + struct st_lex *lex; } %{ @@ -748,6 +749,7 @@ END_OF_INPUT %type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list %type <spcondtype> sp_cond sp_hcond %type <spblock> sp_decls sp_decl +%type <lex> sp_cursor_stmt %type <NONE> '-' '+' '*' '/' '%' '(' ')' @@ -1189,13 +1191,14 @@ sp_proc_stmts: sp_decls: /* Empty */ { - $$.vars= $$.conds= $$.hndlrs= 0; + $$.vars= $$.conds= $$.hndlrs= $$.curs= 0; } | sp_decls sp_decl ';' { $$.vars= $1.vars + $2.vars; $$.conds= $1.conds + $2.conds; $$.hndlrs= $1.hndlrs + $2.hndlrs; + $$.curs= $1.curs + $2.curs; } ; @@ -1222,12 +1225,12 @@ sp_decl: } } $$.vars= $2; - $$.conds= $$.hndlrs= 0; + $$.conds= $$.hndlrs= $$.curs= 0; } | DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond { YYTHD->lex->spcont->push_cond(&$2, $5); - $$.vars= $$.hndlrs= 0; + $$.vars= $$.hndlrs= $$.curs= 0; $$.conds= 1; } | DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM @@ -1260,14 +1263,49 @@ sp_decl: sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */ } lex->sphead->backpatch(hlab); - $$.vars= $$.conds= 0; + $$.vars= $$.conds= $$.curs= 0; $$.hndlrs= $6; } -/* QQ Not yet | DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_instr_cpush *i= new sp_instr_cpush(sp->instructions(), $5); + + sp->add_instr(i); + lex->spcont->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; - }*/ + $$.curs= 1; + } + ; + +sp_cursor_stmt: + { + Lex->sphead->reset_lex(YYTHD); + + /* We use statement here just be able to get a better + error message. Using 'select' works too, but will then + result in a generic "syntax error" if a non-select + statement is given. */ + } + statement + { + LEX *lex= Lex; + + if (lex->sql_command != SQLCOM_SELECT) + { + send_error(YYTHD, ER_SP_BAD_CURSOR_QUERY); + YYABORT; + } + if (lex->result) + { + send_error(YYTHD, ER_SP_BAD_CURSOR_SELECT); + YYABORT; + } + lex->sp_lex_in_use= TRUE; + $$= lex; + lex->sphead->restore_lex(YYTHD); + } ; sp_handler_type: @@ -1506,11 +1544,96 @@ sp_proc_stmt: } } | OPEN_SYM ident - {} - | FETCH_SYM ident INTO select_var_list_init - {} + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint offset; + sp_instr_copen *i; + + if (! lex->spcont->find_cursor(&$2, &offset)) + { + net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str); + YYABORT; + } + i= new sp_instr_copen(sp->instructions(), offset); + sp->add_instr(i); + } + | FETCH_SYM ident INTO + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint offset; + sp_instr_cfetch *i; + + if (! lex->spcont->find_cursor(&$2, &offset)) + { + net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str); + YYABORT; + } + i= new sp_instr_cfetch(sp->instructions(), offset); + sp->add_instr(i); + } + sp_fetch_list + { } | CLOSE_SYM ident - {} + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint offset; + sp_instr_cclose *i; + + if (! lex->spcont->find_cursor(&$2, &offset)) + { + net_printf(YYTHD, ER_SP_CURSOR_MISMATCH, $2.str); + YYABORT; + } + i= new sp_instr_cclose(sp->instructions(), offset); + sp->add_instr(i); + } + ; + +sp_fetch_list: + ident + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *spc= lex->spcont; + sp_pvar_t *spv; + + if (!spc || !(spv = spc->find_pvar(&$1))) + { + net_printf(YYTHD, ER_SP_UNDECLARED_VAR, $1.str); + YYABORT; + } + else + { /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + + i->add_to_varlist(spv); + spv->isset= TRUE; + } + } + | + sp_fetch_list ',' ident + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *spc= lex->spcont; + sp_pvar_t *spv; + + if (!spc || !(spv = spc->find_pvar(&$3))) + { + net_printf(YYTHD, ER_SP_UNDECLARED_VAR, $3.str); + YYABORT; + } + else + { /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + + i->add_to_varlist(spv); + spv->isset= TRUE; + } + } ; sp_if: @@ -1649,11 +1772,11 @@ sp_unlabeled_control: sp->backpatch(ctx->pop_label()); ctx->pop_pvar($3.vars); ctx->pop_cond($3.conds); + ctx->pop_cursor($3.curs); if ($3.hndlrs) - { - sp_instr_hpop *i= new sp_instr_hpop(sp->instructions(),$3.hndlrs); - sp->add_instr(i); - } + sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs)); + if ($3.curs) + sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs)); } | LOOP_SYM sp_proc_stmts END LOOP_SYM @@ -4206,7 +4329,7 @@ select_var_ident: sp_pvar_t *t; if (!(t=lex->spcont->find_pvar(&$1))) { - send_error(lex->thd, ER_SYNTAX_ERROR); + send_error(lex->thd, ER_SP_UNDECLARED_VAR); YYABORT; } if (! lex->result) |