diff options
author | unknown <sergefp@mysql.com> | 2004-05-21 04:27:50 +0400 |
---|---|---|
committer | unknown <sergefp@mysql.com> | 2004-05-21 04:27:50 +0400 |
commit | e7710af7f4c41e77355f5599aafb04999b358292 (patch) | |
tree | a744f3804c5f4a55fabbc3344ef1ec8b1c9e3b52 | |
parent | 201412da7571f5078dae6cdb2067f64a3de5bef8 (diff) | |
download | mariadb-git-e7710af7f4c41e77355f5599aafb04999b358292.tar.gz |
WL#1622 "SQL Syntax for Prepared Statements": Post-review fixes (1 of 2)
mysql-test/r/ps.result:
Added tests for PREPARE stmt1 FROM @var syntax
mysql-test/t/ps.test:
Added tests for PREPARE stmt1 FROM @var syntax
mysys/my_error.c:
Added support for "%.*s" format
sql/item.cc:
Removed one redundant Item_param::set_value function
sql/item.h:
Removed one redundant Item_param::set_value function
sql/mysqld.cc:
Reformmated the code
sql/share/czech/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/dutch/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/english/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/estonian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/french/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/german/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/greek/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/hungarian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/italian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/japanese/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/korean/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/norwegian-ny/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/norwegian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/polish/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/portuguese/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/romanian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/russian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/slovak/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/spanish/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/swedish/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/share/ukrainian/errmsg.txt:
Changed ER_UNKNOWN_STMT_HANDLER format string
sql/sql_class.h:
SQL Prepared statements now can't be used by binary protocol commands
sql/sql_lex.h:
Added support for PREPARE stmt1 FROM @var syntax.
sql/sql_parse.cc:
Added support for PREPARE stmt1 FROM @var syntax.
sql/sql_prepare.cc:
Code cleanup
sql/sql_yacc.yy:
Added support for PREPARE stmt1 FROM @var syntax.
32 files changed, 258 insertions, 80 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index fc82645840c..6c228327b8d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -21,7 +21,7 @@ a b 2 two 3 three deallocate prepare no_such_statement; -ERROR HY000: Undefined prepared statement +ERROR HY000: Unknown prepared statement handler (no_such_statement) given to DEALLOCATE PREPARE execute stmt1; ERROR HY000: Wrong arguments to mysql_execute prepare stmt2 from 'prepare nested_stmt from "select 1"'; @@ -98,4 +98,18 @@ set @arg00=NULL ; prepare stmt1 from 'select 1 FROM t2 where a=?' ; execute stmt1 using @arg00 ; 1 +prepare stmt1 from @nosuchvar; +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 +set @ivar= 1234; +prepare stmt1 from @ivar; +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '1234' at line 1 +set @fvar= 123.4567; +prepare stmt1 from @fvar; +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '123.4567' at line 1 +set @str1 = 'select ?'; +set @str2 = convert(@str1 using ucs2); +prepare stmt1 from @str2; +execute stmt1 using @ivar; +? +1234 drop table t1,t2; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 989dc6026fe..d9e0f0852c5 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -98,5 +98,22 @@ set @arg00=NULL ; prepare stmt1 from 'select 1 FROM t2 where a=?' ; execute stmt1 using @arg00 ; +# prepare using variables: +--error 1064 +prepare stmt1 from @nosuchvar; + +set @ivar= 1234; +--error 1064 +prepare stmt1 from @ivar; + +set @fvar= 123.4567; +--error 1064 +prepare stmt1 from @fvar; + +set @str1 = 'select ?'; +set @str2 = convert(@str1 using ucs2); +prepare stmt1 from @str2; +execute stmt1 using @ivar; + drop table t1,t2; diff --git a/mysys/my_error.c b/mysys/my_error.c index 6fd346c89f7..7ca7dbae8de 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -33,6 +33,12 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; nr Errno MyFlags Flags ... variable list + NOTE + The following subset of printf format is supported: + "%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored. + + Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but + length value is ignored. */ int my_error(int nr,myf MyFlags, ...) @@ -43,7 +49,10 @@ int my_error(int nr,myf MyFlags, ...) reg2 char *endpos; char * par; char ebuff[ERRMSGSIZE+20]; + int prec_chars; + my_bool prec_supplied; DBUG_ENTER("my_error"); + LINT_INIT(prec_chars); /* protected by prec_supplied */ va_start(ap,MyFlags); DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno)); @@ -59,7 +68,6 @@ int my_error(int nr,myf MyFlags, ...) if (tpos[0] != '%') { *endpos++= *tpos++; /* Copy ordinary char */ - olen++; continue; } if (*++tpos == '%') /* test if %% */ @@ -68,21 +76,48 @@ int my_error(int nr,myf MyFlags, ...) } else { - /* Skipp if max size is used (to be compatible with printf) */ - while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' || *tpos == '-') - tpos++; - if (*tpos == 'l') /* Skipp 'l' argument */ - tpos++; + /* + Skip size/precision flags to be compatible with printf. + The only size/precision flag supported is "%.*s". + "%.*u" and "%.*d" cause + */ + prec_supplied= 0; + if (*tpos== '.') + { + tpos++; + olen--; + if (*tpos == '*') + { + tpos++; + olen--; + prec_chars= va_arg(ap, int); /* get length parameter */ + prec_supplied= 1; + } + } + + if (!prec_supplied) + { + while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' || + *tpos == '-') + tpos++; + + if (*tpos == 'l') /* Skipp 'l' argument */ + tpos++; + } + if (*tpos == 's') /* String parameter */ { par = va_arg(ap, char *); plen = (uint) strlen(par); + if (prec_supplied && prec_chars > 0) + plen= min((uint)prec_chars, plen); if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */ { - endpos=strmov(endpos,par); - tpos++; - olen+=plen-2; - continue; + memcpy(endpos,par, plen); + endpos += plen; + tpos++; + olen+=plen-2; + continue; } } else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */ diff --git a/sql/item.cc b/sql/item.cc index b6b99a9f717..8557820474d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -253,7 +253,7 @@ bool Item::get_time(TIME *ltime) return 0; } -CHARSET_INFO * Item::default_charset() const +CHARSET_INFO * Item::default_charset() { return current_thd->variables.collation_connection; } @@ -678,11 +678,6 @@ void Item_param::set_value(const char *str, uint length, CHARSET_INFO *ci) DBUG_VOID_RETURN; } -void Item_param::set_value(const char *str, uint length) -{ - set_value(str, length, default_charset()); -} - void Item_param::set_time(TIME *tm, timestamp_type type) { diff --git a/sql/item.h b/sql/item.h index 471d502a6e1..062e1da990d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -220,7 +220,7 @@ public: virtual Item *real_item() { return this; } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } - CHARSET_INFO *default_charset() const; + static CHARSET_INFO *default_charset(); virtual CHARSET_INFO *compare_collation() { return NULL; } virtual bool walk(Item_processor processor, byte *arg) @@ -413,7 +413,6 @@ public: void set_null(); void set_int(longlong i); void set_double(double i); - void set_value(const char *str, uint length); void set_value(const char *str, uint length, CHARSET_INFO *ci); void set_long_str(const char *str, ulong length); void set_long_binary(const char *str, ulong length); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e810393af60..aa266861dd7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4842,9 +4842,12 @@ struct show_var_st status_vars[]= { {"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG}, {"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG}, {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG}, - {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE), SHOW_LONG}, - {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE), SHOW_LONG}, - {"Com_dealloc_sql", (char*) (com_stat+(uint) SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG}, + {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE), + SHOW_LONG}, + {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE), + SHOW_LONG}, + {"Com_dealloc_sql", (char*) (com_stat+(uint) + SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG}, {"Connections", (char*) &thread_id, SHOW_LONG_CONST}, {"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG}, {"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG}, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index f3a0c5e0eec..f554a1171d3 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -255,7 +255,7 @@ character-set=latin2 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 9d9dfb14a89..0db72a4fb22 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -257,7 +257,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 14a854fbafb..592c44dc3f4 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -246,7 +246,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 5d0f34fd4b2..caa0d8f039e 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -251,7 +251,7 @@ character-set=latin7 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index adc9f66e96b..fb4a2f0f5b1 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -246,7 +246,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 0b732ba48f8..6d484c36116 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -258,7 +258,7 @@ character-set=latin1 "Schlüssel- und Tabellenverweis passen nicht zusammen", "Operand solle %d Spalte(n) enthalten", "Unterabfrage lieferte mehr als einen Datensatz zurück", -"Unbekannter Prepared-Statement-Handler (%ld) für %s angegeben", +"Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben", "Die Hilfe-Datenbank ist beschädigt oder existiert nicht", "Zyklischer Verweis in Unterabfragen", "Spalte '%s' wird von %s nach %s umgewandelt", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index f96c10b0e65..4bea8b2dfc6 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -246,7 +246,7 @@ character-set=greek "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index a26790a4ef9..f7552d6fa15 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -248,7 +248,7 @@ character-set=latin2 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 7c519e4e4bf..0a81a534fbc 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -246,7 +246,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index f973f84d2a4..ce58d87871b 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -248,7 +248,7 @@ character-set=ujis "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 8b5d318ab19..6f3de30c6a5 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -246,7 +246,7 @@ character-set=euckr "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index c0a7d736e1f..1ce737955af 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -248,7 +248,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index fc9b5d2f6da..bb7afd5a8f4 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -248,7 +248,7 @@ character-set=latin1 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 36b7d67d134..b4ff175822a 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -250,7 +250,7 @@ character-set=latin2 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index d4ffa2d5ef5..907ca6fc80c 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -247,7 +247,7 @@ character-set=latin1 "Referência da chave e referência da tabela não coincidem", "Operand should contain %d column(s)", "Subconsulta retorna mais que 1 registro", -"Desconhecido manipulador de declaração preparado (%ld) determinado para %s", +"Desconhecido manipulador de declaração preparado (%.*s) determinado para %s", "Banco de dado de ajuda corrupto ou não existente", "Referência cíclica em subconsultas", "Convertendo coluna '%s' de %s para %s", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 4918a6e1a10..cefd2074bf2 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -250,7 +250,7 @@ character-set=latin2 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index dbc93306a38..f8bf9ea10b2 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -248,7 +248,7 @@ character-set=koi8r "Key reference and table reference doesn't match", "ïÐÅÒÁÎÄ ÄÏÌÖÅÎ ÓÏÄÅÒÖÁÔØ %d ËÏÌÏÎÏË", "ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ", "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 80d21f8e31f..16f9b0a8f35 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -254,7 +254,7 @@ character-set=latin2 "Key reference and table reference doesn't match", "Operand should contain %d column(s)", "Subquery returns more than 1 row", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", "Converting column '%s' from %s to %s", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 512f06c8c50..9ae998184e5 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -248,7 +248,7 @@ character-set=latin1 "Referencia de llave y referencia de tabla no coinciden", "Operando debe tener %d columna(s)", "Subconsulta retorna mas que 1 línea", -"Desconocido preparado comando handler (%ld) dado para %s", +"Desconocido preparado comando handler (%.*s) dado para %s", "Base de datos Help está corrupto o no existe", "Cíclica referencia en subconsultas", "Convirtiendo columna '%s' de %s para %s", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 22e7cb786b5..aed3e9d3d34 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -246,7 +246,7 @@ character-set=latin1 "Nyckelreferensen och tabellreferensen stämmer inte överens", "Operand should contain %d column(s)", "Subquery returnerade mer än 1 rad", -"Okänd PREPARED STATEMENT id (%ld) var given till %s", +"Okänd PREPARED STATEMENT id (%.*s) var given till %s", "Hjälpdatabasen finns inte eller är skadad", "Cyklisk referens i subqueries", "Konvertar kolumn '%s' från %s till %s", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 3149d58b413..c0ccd76f157 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -251,7 +251,7 @@ character-set=koi8u "Key reference and table reference doesn't match", "ïÐÅÒÁÎÄ ÍÁ¤ ÓËÌÁÄÁÔÉÓÑ Ú %d ÓÔÏ×Âæ×", "ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ", -"Unknown prepared statement handler (%ld) given to %s", +"Unknown prepared statement handler (%.*s) given to %s", "Help database is corrupt or does not exist", "ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ", "ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s", diff --git a/sql/sql_class.h b/sql/sql_class.h index f208a3f4d73..b5774688e1e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -556,8 +556,13 @@ public: Statement *find(ulong id) { if (last_found_statement == 0 || id != last_found_statement->id) - last_found_statement= (Statement *) hash_search(&st_hash, (byte *) &id, - sizeof(id)); + { + Statement *stmt; + stmt= (Statement *) hash_search(&st_hash, (byte *) &id, sizeof(id)); + if (stmt->name.str) + return NULL; + last_found_statement= stmt; + } return last_found_statement; } void erase(Statement *statement) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a525bc485c1..9bea0de7b39 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -608,7 +608,13 @@ typedef struct st_lex bool safe_to_cache_query; /* Prepared statements SQL syntax:*/ LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */ - LEX_STRING prepared_stmt_code; /* Statement query (in PREPARE )*/ + /* + Prepared statement query text or name of variable that holds the + prepared statement (in PREPARE ... queries) + */ + LEX_STRING prepared_stmt_code; + /* If true, prepared_stmt_code is a name of variable that holds the query */ + bool prepared_stmt_code_is_varref; /* Names of user variables holding parameters (in EXECUTE) */ List<LEX_STRING> prepared_stmt_params; st_lex() {} diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 65d538e3ac4..cd8891ad326 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1972,14 +1972,90 @@ mysql_execute_command(THD *thd) } case SQLCOM_PREPARE: { - DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n", - lex->prepared_stmt_name.length, - lex->prepared_stmt_name.str, - lex->prepared_stmt_code.length, - lex->prepared_stmt_code.str)); + char *query_str; + uint query_len; + if (lex->prepared_stmt_code_is_varref) + { + /* This is PREPARE stmt FROM @var*/ + String str; + CHARSET_INFO *to_cs= thd->variables.collation_connection; + CHARSET_INFO *from_cs; + const char *buf; + uint buf_len; + bool need_conversion; + //// psergey: find the variable and convert it. + LINT_INIT(from_cs); + user_var_entry *entry; + uint32 unused; + if ((entry= + (user_var_entry*)hash_search(&thd->user_vars, + (byte*)lex->prepared_stmt_code.str, + lex->prepared_stmt_code.length)) + && entry->value) + { + switch (entry->type) + { + case REAL_RESULT: + str.set(*(double*)entry->value, NOT_FIXED_DEC, to_cs); + buf_len= str.length(); + buf= str.ptr(); + need_conversion= false; + break; + case INT_RESULT: + str.set(*(longlong*)entry->value, to_cs); + buf_len= str.length(); + buf= str.ptr(); + need_conversion= false; + break; + case STRING_RESULT: + buf_len= entry->length; + buf= entry->value; + from_cs = entry->collation.collation; + need_conversion= String::needs_conversion(entry->length, from_cs, + to_cs, &unused); + break; + default: + buf= ""; + need_conversion= false; + buf_len= 0; + DBUG_ASSERT(0); + } + } + else + { + from_cs= &my_charset_bin; + str.set("NULL", 4, from_cs); + buf= str.ptr(); + buf_len= str.length(); + need_conversion= String::needs_conversion(str.length(), from_cs, + to_cs, &unused); + } + + query_len = need_conversion? (buf_len* to_cs->mbmaxlen) : buf_len; + if (!(query_str= alloc_root(&thd->mem_root, query_len+1))) + { + send_error(thd, ER_OUT_OF_RESOURCES); + } + + if (need_conversion) + query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len, + from_cs); + else + memcpy(query_str, buf, query_len); + query_str[query_len] = 0; + } + else + { + DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n", + lex->prepared_stmt_name.length, + lex->prepared_stmt_name.str, + lex->prepared_stmt_code.length, + lex->prepared_stmt_code.str)); + query_str= lex->prepared_stmt_code.str; + query_len= lex->prepared_stmt_code.length + 1; + } thd->command= COM_PREPARE; - if (!mysql_stmt_prepare(thd, lex->prepared_stmt_code.str, - lex->prepared_stmt_code.length + 1, + if (!mysql_stmt_prepare(thd, query_str, query_len + 1, &lex->prepared_stmt_name)) send_ok(thd, 0L, 0L, "Statement prepared"); break; @@ -2005,7 +2081,12 @@ mysql_execute_command(THD *thd) send_ok(thd); } else - send_error(thd,ER_UNKNOWN_STMT_HANDLER,"Undefined prepared statement"); + { + res= -1; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), + lex->prepared_stmt_name.length, lex->prepared_stmt_name.str, + "DEALLOCATE PREPARE"); + } break; } case SQLCOM_DO: @@ -3438,7 +3519,7 @@ error: */ int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables) - + { if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0)) return 1; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1612432cd67..af489d20783 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -135,7 +135,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where, if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT) { - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), id, where); + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where); if (se == SEND_ERROR) send_error(thd); return 0; @@ -392,7 +393,7 @@ void set_param_date(Item_param *param, uchar **pos, ulong len) void set_param_str(Item_param *param, uchar **pos, ulong len) { ulong length= get_param_length(pos, len); - param->set_value((const char *)*pos, length); + param->set_value((const char *)*pos, length, Item::default_charset()); *pos+= length; } @@ -1376,7 +1377,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) goto error; } if (res == 0) - DBUG_RETURN(text_protocol?0:send_prep_stmt(stmt, 0)); + DBUG_RETURN(text_protocol? 0 : send_prep_stmt(stmt, 0)); error: if (res < 0) send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0); @@ -1417,25 +1418,31 @@ static bool init_param_array(Prepared_statement *stmt) /* + Given a query string with parameter markers, create a Prepared Statement + from it and send PS info back to the client. + SYNOPSIS mysql_stmt_prepare() - packet Prepared query - packet_length query length, with ignored trailing NULL or quote char. + packet query to be prepared + packet_length query string length, including ignored trailing NULL or + quote char. name NULL or statement name. For unnamed statements binary PS - protocol is used, for named statmenents text protocol is + protocol is used, for named statements text protocol is used. - - Parse the query and send the total number of parameters - and resultset metadata information back to client (if any), - without executing the query i.e. without any log/disk - writes. This will allow the queries to be re-executed - without re-parsing during execute. - - If parameter markers are found in the query, then store - the information using Item_param along with maintaining a - list in lex->param_array, so that a fast and direct - retrieval can be made without going through all field - items. + RETURN + 0 OK, statement prepared successfully + other Error + + NOTES + This function parses the query and sends the total number of parameters + and resultset metadata information back to client (if any), without + executing the query i.e. without any log/disk writes. This allows the + queries to be re-executed without re-parsing during execute. + + If parameter markers are found in the query, then store the information + using Item_param along with maintaining a list in lex->param_array, so + that a fast and direct retrieval can be made without going through all + field items. */ @@ -1672,13 +1679,14 @@ set_params_data_err: void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) { Prepared_statement *stmt; - DBUG_ENTER("mysql_stmt_execute"); + DBUG_ENTER("mysql_sql_stmt_execute"); if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name))) { - send_error(thd, ER_UNKNOWN_STMT_HANDLER, - "Undefined prepared statement"); - DBUG_VOID_RETURN; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length, + stmt_name->str, "EXECUTE"); + send_error(thd); + DBUG_VOID_RETURN; } if (stmt->param_count != thd->lex->prepared_stmt_params.elements) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6a683a26b01..bb226f76b2c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -726,7 +726,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len opt_extended_describe - prepare execute deallocate + prepare prepare_src execute deallocate END_OF_INPUT %type <NONE> @@ -816,7 +816,7 @@ deallocate: }; prepare: - PREPARE_SYM ident FROM TEXT_STRING_sys + PREPARE_SYM ident FROM prepare_src { THD *thd=YYTHD; LEX *lex= thd->lex; @@ -827,9 +827,24 @@ prepare: } lex->sql_command= SQLCOM_PREPARE; lex->prepared_stmt_name= $2; - lex->prepared_stmt_code= $4; }; +prepare_src: + TEXT_STRING_sys + { + THD *thd=YYTHD; + LEX *lex= thd->lex; + lex->prepared_stmt_code= $1; + lex->prepared_stmt_code_is_varref= false; + } + | '@' ident_or_text + { + THD *thd=YYTHD; + LEX *lex= thd->lex; + lex->prepared_stmt_code= $2; + lex->prepared_stmt_code_is_varref= true; + }; + execute: EXECUTE_SYM ident { |