summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <pem@mysql.telia.com>2003-10-10 16:57:21 +0200
committerunknown <pem@mysql.telia.com>2003-10-10 16:57:21 +0200
commit04c6b9b8d8c10fd83ab80f1a3e2d6bd58b34b825 (patch)
tree502f5a108855c24da25af7d42aa635d0a3c5103b /sql
parent4379cbcf3056a33f41ddf489828203a6c03e793f (diff)
downloadmariadb-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')
-rw-r--r--sql/protocol.cc9
-rw-r--r--sql/protocol.h8
-rw-r--r--sql/protocol_cursor.cc12
-rw-r--r--sql/share/czech/errmsg.txt8
-rw-r--r--sql/share/danish/errmsg.txt8
-rw-r--r--sql/share/dutch/errmsg.txt8
-rw-r--r--sql/share/english/errmsg.txt8
-rw-r--r--sql/share/estonian/errmsg.txt8
-rw-r--r--sql/share/french/errmsg.txt8
-rw-r--r--sql/share/german/errmsg.txt8
-rw-r--r--sql/share/greek/errmsg.txt8
-rw-r--r--sql/share/hungarian/errmsg.txt8
-rw-r--r--sql/share/italian/errmsg.txt8
-rw-r--r--sql/share/japanese/errmsg.txt8
-rw-r--r--sql/share/korean/errmsg.txt8
-rw-r--r--sql/share/norwegian-ny/errmsg.txt8
-rw-r--r--sql/share/norwegian/errmsg.txt8
-rw-r--r--sql/share/polish/errmsg.txt8
-rw-r--r--sql/share/portuguese/errmsg.txt8
-rw-r--r--sql/share/romanian/errmsg.txt8
-rw-r--r--sql/share/russian/errmsg.txt8
-rw-r--r--sql/share/serbian/errmsg.txt8
-rw-r--r--sql/share/slovak/errmsg.txt8
-rw-r--r--sql/share/spanish/errmsg.txt8
-rw-r--r--sql/share/swedish/errmsg.txt8
-rw-r--r--sql/share/ukrainian/errmsg.txt8
-rw-r--r--sql/sp_head.cc153
-rw-r--r--sql/sp_head.h129
-rw-r--r--sql/sp_pcontext.cc42
-rw-r--r--sql/sp_pcontext.h28
-rw-r--r--sql/sp_rcontext.cc146
-rw-r--r--sql/sp_rcontext.h79
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_yacc.yy155
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)