summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysql.cc4
-rw-r--r--include/config-win.h1
-rw-r--r--include/errmsg.h4
-rw-r--r--include/m_string.h3
-rw-r--r--include/my_global.h8
-rw-r--r--include/mysql.h52
-rw-r--r--include/mysqld_error.h3
-rw-r--r--include/sql_common.h1
-rw-r--r--libmysql/client_settings.h1
-rw-r--r--libmysql/errmsg.c16
-rw-r--r--libmysql/libmysql.c579
-rw-r--r--mysql-test/r/create.result16
-rw-r--r--mysql-test/r/date_formats.result113
-rw-r--r--mysql-test/r/func_sapdb.result15
-rw-r--r--mysql-test/r/func_str.result3
-rw-r--r--mysql-test/r/func_time.result27
-rw-r--r--mysql-test/r/subselect.result6
-rw-r--r--mysql-test/r/type_time.result2
-rw-r--r--mysql-test/t/date_formats.test31
-rw-r--r--mysql-test/t/func_sapdb.test6
-rw-r--r--mysql-test/t/func_str.test7
-rw-r--r--mysql-test/t/func_time.test10
-rw-r--r--mysql-test/t/subselect.test7
-rw-r--r--sql-common/client.c98
-rw-r--r--sql/item.cc61
-rw-r--r--sql/item.h24
-rw-r--r--sql/item_cmpfunc.cc5
-rw-r--r--sql/item_func.cc48
-rw-r--r--sql/item_func.h4
-rw-r--r--sql/item_row.cc18
-rw-r--r--sql/item_strfunc.cc4
-rw-r--r--sql/item_subselect.cc5
-rw-r--r--sql/item_sum.cc10
-rw-r--r--sql/item_timefunc.cc287
-rw-r--r--sql/item_timefunc.h43
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/log_event.cc4
-rw-r--r--sql/mysql_priv.h13
-rw-r--r--sql/mysqld.cc8
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/share/czech/errmsg.txt1
-rw-r--r--sql/share/danish/errmsg.txt1
-rw-r--r--sql/share/dutch/errmsg.txt1
-rw-r--r--sql/share/english/errmsg.txt1
-rw-r--r--sql/share/estonian/errmsg.txt1
-rw-r--r--sql/share/french/errmsg.txt1
-rw-r--r--sql/share/german/errmsg.txt1
-rw-r--r--sql/share/greek/errmsg.txt1
-rw-r--r--sql/share/hungarian/errmsg.txt1
-rw-r--r--sql/share/italian/errmsg.txt1
-rw-r--r--sql/share/japanese/errmsg.txt1
-rw-r--r--sql/share/korean/errmsg.txt1
-rw-r--r--sql/share/norwegian-ny/errmsg.txt1
-rw-r--r--sql/share/norwegian/errmsg.txt1
-rw-r--r--sql/share/polish/errmsg.txt1
-rw-r--r--sql/share/portuguese/errmsg.txt1
-rw-r--r--sql/share/romanian/errmsg.txt1
-rw-r--r--sql/share/russian/errmsg.txt1
-rw-r--r--sql/share/serbian/errmsg.txt1
-rw-r--r--sql/share/slovak/errmsg.txt1
-rw-r--r--sql/share/spanish/errmsg.txt1
-rw-r--r--sql/share/swedish/errmsg.txt1
-rw-r--r--sql/share/ukrainian/errmsg.txt1
-rw-r--r--sql/spatial.cc4
-rw-r--r--sql/spatial.h5
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc115
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc3
-rw-r--r--sql/sql_table.cc15
-rw-r--r--sql/time.cc80
-rw-r--r--strings/ctype-simple.c16
-rw-r--r--strings/strtod.c21
77 files changed, 1295 insertions, 559 deletions
diff --git a/client/mysql.cc b/client/mysql.cc
index 5d69d3838ee..82925400c44 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -619,10 +619,10 @@ static struct my_option my_long_options[] =
(gptr*) &current_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"safe-updates", 'U', "Only allow UPDATE and DELETE that uses keys.",
- (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, OPT_ARG, 0, 0,
+ (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
{"i-am-a-dummy", 'U', "Synonym for option --safe-updates, -U.",
- (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, OPT_ARG, 0, 0,
+ (gptr*) &safe_updates, (gptr*) &safe_updates, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
{"verbose", 'v', "Write more. (-v -v -v gives the table output format).", 0,
0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/include/config-win.h b/include/config-win.h
index abc1aa7a6ee..518f445861a 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -95,6 +95,7 @@ functions */
#define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF)
#define ULONGLONG_MAX ((unsigned __int64) 0xFFFFFFFFFFFFFFFF)
#define LL(A) ((__int64) A)
+#define ULL(A) ((unsigned __int64) A)
/* Type information */
diff --git a/include/errmsg.h b/include/errmsg.h
index 8f3ddfa9796..16f220a7ee2 100644
--- a/include/errmsg.h
+++ b/include/errmsg.h
@@ -67,7 +67,7 @@ extern const char *client_errors[]; /* Error messages */
/* new 4.1 error codes */
#define CR_NULL_POINTER 2028
#define CR_NO_PREPARE_STMT 2029
-#define CR_NOT_ALL_PARAMS_BOUND 2030
+#define CR_PARAMS_NOT_BOUND 2030
#define CR_DATA_TRUNCATED 2031
#define CR_NO_PARAMETERS_EXISTS 2032
#define CR_INVALID_PARAMETER_NO 2033
@@ -87,3 +87,5 @@ extern const char *client_errors[]; /* Error messages */
#define CR_CONN_UNKNOW_PROTOCOL 2046
#define CR_INVALID_CONN_HANDLE 2047
#define CR_SECURE_AUTH 2048
+#define CR_FETCH_CANCELLED 2049
+#define CR_NO_DATA 2050
diff --git a/include/m_string.h b/include/m_string.h
index 73c8a385a70..21aa736acd4 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -218,9 +218,6 @@ extern int is_prefix(const char *, const char *);
/* Conversion routines */
double my_strtod(const char *str, char **end);
double my_atof(const char *nptr);
-#ifndef EOVERFLOW
-#define EOVERFLOW 84
-#endif
#ifdef USE_MY_ITOA
extern char *my_itoa(int val,char *dst,int radix);
diff --git a/include/my_global.h b/include/my_global.h
index 2a82173979d..4a56741ddbc 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -842,6 +842,14 @@ typedef char bool; /* Ordinary boolean values 0 1 */
#endif
#endif
+#ifndef ULL
+#ifdef HAVE_LONG_LONG
+#define ULL(A) A ## ULL
+#else
+#define ULL(A) A ## UL
+#endif
+#endif
+
/*
Defines to make it possible to prioritize register assignments. No
longer that important with modern compilers.
diff --git a/include/mysql.h b/include/mysql.h
index 2b4153bb140..1bcc2a58534 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -256,6 +256,11 @@ typedef struct st_mysql
LIST *stmts; /* list of all statements */
const struct st_mysql_methods *methods;
void *thd;
+ /*
+ Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag
+ from mysql_stmt_close if close had to cancel result set of this object.
+ */
+ my_bool *unbuffered_fetch_owner;
} MYSQL;
typedef struct st_mysql_res {
@@ -270,6 +275,8 @@ typedef struct st_mysql_res {
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
my_bool eof; /* Used by mysql_fetch_row */
+ /* mysql_stmt_close() had to cancel this result */
+ my_bool unbuffered_fetch_cancelled;
const struct st_mysql_methods *methods;
} MYSQL_RES;
@@ -479,7 +486,11 @@ my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
*/
/* statement state */
-enum PREP_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE };
+enum enum_mysql_stmt_state
+{
+ MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE,
+ MYSQL_STMT_FETCH_DONE
+};
/*
client TIME structure to handle TIME, DATE and TIMESTAMP directly in
@@ -525,31 +536,34 @@ typedef struct st_mysql_bind
/* statement handler */
typedef struct st_mysql_stmt
{
- MYSQL *mysql; /* connection handle */
- MYSQL_BIND *params; /* input parameters */
- MYSQL_RES *result; /* resultset */
- MYSQL_BIND *bind; /* row binding */
- MYSQL_FIELD *fields; /* prepare meta info */
+ MEM_ROOT mem_root; /* root allocations */
LIST list; /* list to keep track of all stmts */
- unsigned char *current_row; /* unbuffered row */
- unsigned char *last_fetched_buffer; /* last fetched column buffer */
- char *query; /* query buffer */
- MEM_ROOT mem_root; /* root allocations */
- my_ulonglong last_fetched_column; /* last fetched column */
+ MYSQL *mysql; /* connection handle */
+ MYSQL_BIND *params; /* input parameters */
+ MYSQL_BIND *bind; /* output parameters */
+ MYSQL_FIELD *fields; /* result set metadata */
+ MYSQL_RES *result; /* cached result set */
/* copy of mysql->affected_rows after statement execution */
my_ulonglong affected_rows;
+ /*
+ mysql_stmt_fetch() calls this function to fetch one row (it's different
+ for buffered, unbuffered and cursor fetch).
+ */
+ int (*read_row_func)(struct st_mysql_stmt *stmt,
+ unsigned char **row);
unsigned long stmt_id; /* Id for prepared statement */
unsigned int last_errno; /* error code */
- unsigned int param_count; /* parameters count */
- unsigned int field_count; /* fields count */
- enum PREP_STMT_STATE state; /* statement state */
+ unsigned int param_count; /* inpute parameters count */
+ unsigned int field_count; /* number of columns in result set */
+ enum enum_mysql_stmt_state state; /* statement state */
char last_error[MYSQL_ERRMSG_SIZE]; /* error message */
char sqlstate[SQLSTATE_LENGTH+1];
- my_bool long_alloced; /* flag to indicate long alloced */
- my_bool send_types_to_server; /* Types sent to server */
- my_bool param_buffers; /* param bound buffers */
- my_bool res_buffers; /* output bound buffers */
- my_bool result_buffered; /* Results buffered */
+ /* Types of input parameters should be sent to server */
+ my_bool send_types_to_server;
+ my_bool bind_param_done; /* input buffers were supplied */
+ my_bool bind_result_done; /* output buffers were supplied */
+ /* mysql_stmt_close() had to cancel this result */
+ my_bool unbuffered_fetch_cancelled;
} MYSQL_STMT;
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 2a7623b6947..77164e637cb 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -308,4 +308,5 @@
#define ER_FEATURE_DISABLED 1289
#define ER_OPTION_PREVENTS_STATEMENT 1290
#define ER_DUPLICATED_VALUE_IN_TYPE 1291
-#define ER_ERROR_MESSAGES 292
+#define ER_TRUNCATED_WRONG_VALUE 1292
+#define ER_ERROR_MESSAGES 293
diff --git a/include/sql_common.h b/include/sql_common.h
index cde53786f83..3f50008a922 100644
--- a/include/sql_common.h
+++ b/include/sql_common.h
@@ -25,6 +25,7 @@ extern "C" {
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
my_bool default_value, uint server_capabilities);
void free_rows(MYSQL_DATA *cur);
+void flush_use_result(MYSQL *mysql);
my_bool mysql_autenticate(MYSQL *mysql, const char *passwd);
void free_old_query(MYSQL *mysql);
void end_server(MYSQL *mysql);
diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h
index e4475d76958..9fc8e67df27 100644
--- a/libmysql/client_settings.h
+++ b/libmysql/client_settings.h
@@ -22,7 +22,6 @@ extern my_string mysql_unix_port;
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
sig_handler pipe_sig_handler(int sig __attribute__((unused)));
-my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_free);
void read_user_name(char *name);
my_bool send_file_to_server(MYSQL *mysql, const char *filename);
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 569267ddb37..e651c13897f 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -54,7 +54,7 @@ const char *client_errors[]=
"Malformed packet",
"Invalid use of null pointer",
"Statement not prepared",
- "Not all parameters data supplied",
+ "Parameters data was not supplied",
"Data truncated",
"No parameters exists in the statement",
"Invalid parameter number",
@@ -72,7 +72,9 @@ const char *client_errors[]=
"Can't open shared memory. Can't send the request event to server (%lu)",
"Wrong or unknown protocol",
"Invalid connection handle",
- "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
+ "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
+ "Row retrieval was cancelled by mysql_stmt_close() call",
+ "Attempt to read column without prior row fetch"
};
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
@@ -110,7 +112,7 @@ const char *client_errors[]=
"Malformed packet",
"Invalid use of null pointer",
"Statement not prepared",
- "Not all parameters data supplied",
+ "Parameters data was not supplied",
"Data truncated",
"No parameters exists in the statement",
"Invalid parameter number",
@@ -128,7 +130,9 @@ const char *client_errors[]=
"Can't open shared memory. Can't send the request event to server (%lu)",
"Wrong or unknown protocol",
"Invalid connection handle",
- "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
+ "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
+ "Row retrieval was cancelled by mysql_stmt_close() call",
+ "Attempt to read column without prior row fetch"
};
#else /* ENGLISH */
@@ -182,7 +186,9 @@ const char *client_errors[]=
"Can't open shared memory. Can't send the request event to server (%lu)",
"Wrong or unknown protocol",
"Invalid connection handle",
- "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
+ "Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
+ "Row retrieval was cancelled by mysql_stmt_close() call",
+ "Attempt to read column without prior row fetch"
};
#endif
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 0f274021f20..91927e44e49 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -638,6 +638,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
return 0;
}
+
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
@@ -866,6 +867,7 @@ STDCALL mysql_set_master(MYSQL* mysql, const char* host,
return 0;
}
+
int
STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
unsigned int port,
@@ -987,6 +989,7 @@ mysql_list_tables(MYSQL *mysql, const char *wild)
DBUG_RETURN (mysql_store_result(mysql));
}
+
MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
{
MYSQL_DATA *query;
@@ -1062,6 +1065,7 @@ mysql_list_processes(MYSQL *mysql)
DBUG_RETURN(mysql_store_result(mysql));
}
+
#ifdef USE_OLD_FUNCTIONS
int STDCALL
mysql_create_db(MYSQL *mysql, const char *db)
@@ -1099,6 +1103,7 @@ mysql_refresh(MYSQL *mysql,uint options)
DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
}
+
int STDCALL
mysql_kill(MYSQL *mysql,ulong pid)
{
@@ -1126,6 +1131,7 @@ mysql_dump_debug_info(MYSQL *mysql)
DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
}
+
const char *cli_read_statistics(MYSQL *mysql)
{
mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
@@ -1139,6 +1145,7 @@ const char *cli_read_statistics(MYSQL *mysql)
return (char*) mysql->net.read_pos;
}
+
const char * STDCALL
mysql_stat(MYSQL *mysql)
{
@@ -1576,6 +1583,10 @@ static my_bool my_realloc_str(NET *net, ulong length)
Prepare related implementations
********************************************************************/
+static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row);
+static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row);
+static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
+
/*
Read the prepared statement results ..
@@ -1591,13 +1602,12 @@ static my_bool my_realloc_str(NET *net, ulong length)
my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
{
uchar *pos;
- uint field_count;
- ulong length, param_count;
+ uint field_count, param_count;
MYSQL_DATA *fields_data;
DBUG_ENTER("read_prepare_result");
mysql= mysql->last_used_con;
- if ((length= net_safe_read(mysql)) == packet_error)
+ if (net_safe_read(mysql) == packet_error)
DBUG_RETURN(1);
pos= (uchar*) mysql->net.read_pos;
@@ -1634,7 +1644,7 @@ MYSQL_STMT * STDCALL mysql_prepare(MYSQL *mysql, const char *query,
stmt= mysql_stmt_init(mysql);
if (stmt && mysql_stmt_prepare(stmt, query, query_length))
{
- stmt_close(stmt, 0);
+ mysql_stmt_close(stmt);
DBUG_RETURN(0);
}
DBUG_RETURN(stmt);
@@ -1646,6 +1656,7 @@ MYSQL_STMT * STDCALL mysql_prepare(MYSQL *mysql, const char *query,
SYNOPSIS
mysql_stmt_init()
mysql connection handle
+
RETURN VALUE
statement structure upon success and NULL if out of
memory
@@ -1664,20 +1675,35 @@ mysql_stmt_init(MYSQL *mysql)
DBUG_RETURN(0);
}
- init_alloc_root(&stmt->mem_root,8192,0);
+ init_alloc_root(&stmt->mem_root, 2048, 2048);
mysql->stmts= list_add(mysql->stmts, &stmt->list);
stmt->list.data= stmt;
- stmt->state= MY_ST_UNKNOWN;
+ stmt->state= MYSQL_STMT_INIT_DONE;
stmt->mysql= mysql;
+ stmt->read_row_func= stmt_read_row_no_data;
+ /* The rest of statement members was bzeroed inside malloc */
DBUG_RETURN(stmt);
}
/*
- Prepare server side statement with query.
+ Prepare server side statement with query:
+ SYNOPSIS
+ mysql_stmt_prepare()
+ query statement to prepare
+ length statement length
+
+ DESCRIPTION
+ - if this is a re-prepare of the statement, first close previous data
+ structure on the server and free old statement data
+ - send the query to server and get back number of placeholders,
+ number of columns in result set (if any), and result set metadata.
+ At the same time allocate memory for input and output parameters
+ to have less checks in mysql_stmt_bind_{param, result}.
- Also update the total parameter count along with resultset
- metadata information by reading from server
+ RETURN VALUES
+ 0 success
+ !0 error
*/
@@ -1687,17 +1713,44 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
MYSQL *mysql= stmt->mysql;
DBUG_ENTER("mysql_stmt_prepare");
- DBUG_ASSERT(mysql != 0);
-
- /* In case we reprepare this handle with another statement */
- free_root(&stmt->mem_root, MYF(0));
-
- /* stmt->query is never used yet */
- if (!(stmt->query= strmake_root(&stmt->mem_root, query, length)))
+ if (!mysql)
{
- set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ /* mysql can be reset in mysql_close called from mysql_reconnect */
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
DBUG_RETURN(1);
}
+
+ if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
+ {
+ /* This is second prepare with another statement */
+ char buff[4];
+
+ mysql_stmt_free_result(stmt);
+ /*
+ These members must be reset for API to
+ function in case of error or misuse.
+ */
+ stmt->bind_param_done= stmt->bind_result_done= FALSE;
+ stmt->param_count= stmt->field_count= 0;
+ stmt->last_errno= 0;
+ stmt->last_error[0]= '\0';
+ free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
+
+ int4store(buff, stmt->stmt_id);
+ /*
+ If there was a 'use' result from another statement, or from
+ mysql_use_result it won't be freed in mysql_stmt_free_result and
+ we should get 'Commands out of sync' here.
+ */
+ if (simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
+ {
+ set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
+ mysql->net.sqlstate);
+ DBUG_RETURN(1);
+ }
+ stmt->state= MYSQL_STMT_INIT_DONE;
+ }
+
if (simple_command(mysql, COM_PREPARE, query, length, 1))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
@@ -1706,8 +1759,18 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
}
if ((*mysql->methods->read_prepare_result)(mysql, stmt))
+ {
+ set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
+ mysql->net.sqlstate);
DBUG_RETURN(1);
+ }
+ /*
+ alloc_root will return valid address even in case param_count
+ and field_count are zero. Thus we should never rely on stmt->bind
+ or stmt->params when checking for existence of placeholders or
+ result set.
+ */
if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root,
sizeof(MYSQL_BIND)*
(stmt->param_count +
@@ -1717,26 +1780,22 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
DBUG_RETURN(1);
}
stmt->bind= stmt->params + stmt->param_count;
- stmt->state= MY_ST_PREPARE;
- mysql->status= MYSQL_STATUS_READY;
+ stmt->state= MYSQL_STMT_PREPARE_DONE;
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
DBUG_RETURN(0);
}
/*
Get the execute query meta information for non-select
- statements (on demand).
+ statements.
*/
-unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
+static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
{
MYSQL_FIELD *fields, *field, *end;
MEM_ROOT *alloc= &stmt->mem_root;
MYSQL *mysql= stmt->mysql->last_used_con;
- if (stmt->state != MY_ST_EXECUTE || !mysql->field_count)
- return 0;
-
stmt->field_count= mysql->field_count;
/*
@@ -1782,20 +1841,25 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt)
MYSQL_RES *result;
DBUG_ENTER("mysql_stmt_result_metadata");
- if (!stmt->field_count || !stmt->fields)
+ /*
+ stmt->fields is only defined if stmt->field_count is not null;
+ stmt->field_count is initialized in prepare.
+ */
+ if (!stmt->field_count)
+ DBUG_RETURN(0);
+
+ if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result),
+ MYF(MY_WME | MY_ZEROFILL))))
{
- if (!alloc_stmt_fields(stmt))
- DBUG_RETURN(0);
- }
- if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
- sizeof(ulong)*stmt->field_count,
- MYF(MY_WME | MY_ZEROFILL))))
- return 0;
+ set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ DBUG_RETURN(0);
+ }
- result->methods= stmt->mysql->methods;
- result->eof=1; /* Marker for buffered */
+ result->methods= stmt->mysql->methods;
+ result->eof= 1; /* Marker for buffered */
result->fields= stmt->fields;
result->field_count= stmt->field_count;
+ /* The rest of members of 'result' was bzeroed inside malloc */
DBUG_RETURN(result);
}
@@ -1989,11 +2053,9 @@ static void store_param_null(NET *net, MYSQL_BIND *param)
client application
*/
-
static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
{
- MYSQL *mysql= stmt->mysql;
- NET *net = &mysql->net;
+ NET *net= &stmt->mysql->net;
DBUG_ENTER("store_param");
DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %lu is_null: %d",
param->buffer_type,
@@ -2059,6 +2121,12 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
uint null_count;
my_bool result;
+ if (!stmt->bind_param_done)
+ {
+ set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+
net_clear(net); /* Sets net->write_pos */
/* Reserve place for null-marker bytes */
null_count= (stmt->param_count+7) /8;
@@ -2093,7 +2161,6 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
DBUG_RETURN(1);
}
- net->write_pos= net->buff; /* Reset for net_write() */
result= execute(stmt, param_data, length);
stmt->send_types_to_server=0;
my_free(param_data, MYF(MY_WME));
@@ -2103,21 +2170,145 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
}
/*
+ Read one row from buffered result set. Result set is created by prior
+ call to mysql_stmt_store_result().
+ SYNOPSIS
+ stmt_read_row_buffered()
+
+ RETURN VALUE
+ 0 - success; *row is set to valid row pointer (row data
+ is stored in result set buffer)
+ MYSQL_NO_DATA - end of result set. *row is set to NULL
+*/
+
+static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row)
+{
+ MYSQL_RES *result= stmt->result;
+
+ if (result && result->data_cursor)
+ {
+ *row= (uchar *) result->data_cursor->data;
+ result->data_cursor= result->data_cursor->next;
+ return 0;
+ }
+ *row= 0;
+ return MYSQL_NO_DATA;
+}
+
+/*
+ Read one row from network: unbuffered non-cursor fetch.
+ If last row was read, or error occured, erase this statement
+ from record pointing to object unbuffered fetch is performed from.
+
+ SYNOPSIS
+ stmt_read_row_unbuffered()
+ stmt statement handle
+ row pointer to write pointer to row data;
+
+ RETURN VALUE
+ 0 - success; *row contains valid address of a row;
+ row data is stored in network buffer
+ 1 - error; error code is written to
+ stmt->last_{errno,error}; *row is not changed
+ MYSQL_NO_DATA - end of file was read from network;
+ *row is to NULL
+*/
+
+static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row)
+{
+ int rc= 1;
+ MYSQL *mysql= stmt->mysql;
+ /*
+ This function won't be called if stmt->field_count is zero
+ or execution wasn't done: this is ensured by mysql_stmt_execute.
+ */
+ if (!mysql)
+ {
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ return 1;
+ }
+ if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ {
+ set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
+ CR_FETCH_CANCELLED : CR_COMMANDS_OUT_OF_SYNC,
+ unknown_sqlstate);
+ goto error;
+ }
+ if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row))
+ {
+ set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
+ mysql->net.sqlstate);
+ goto error;
+ }
+ if (!*row)
+ {
+ mysql->status= MYSQL_STATUS_READY;
+ rc= MYSQL_NO_DATA;
+ goto error;
+ }
+ return 0;
+error:
+ if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ return rc;
+}
+
+/*
+ Default read row function to not SIGSEGV in client in
+ case of wrong sequence of API calls.
+*/
+
+static int
+stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
+ unsigned char **row __attribute__((unused)))
+{
+ if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
+ {
+ set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
+ return 1;
+ }
+ return MYSQL_NO_DATA;
+}
+
+/*
Execute the prepared query
*/
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
{
+ MYSQL *mysql= stmt->mysql;
DBUG_ENTER("mysql_stmt_execute");
- if ((*stmt->mysql->methods->stmt_execute)(stmt))
+ if (!mysql)
+ {
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
DBUG_RETURN(1);
+ }
+
+ mysql_stmt_free_result(stmt);
+ /*
+ No need to check for stmt->state: if the statement wasn't
+ prepared we'll get 'unknown statemenet handler' error from server.
+ */
+ if (mysql->methods->stmt_execute(stmt))
+ DBUG_RETURN(1);
+ if (!stmt->field_count && mysql->field_count)
+ {
+ /*
+ This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
+ prepared statements can't send result set metadata for this queries
+ on prepare stage. Read it now.
+ */
+ alloc_stmt_fields(stmt);
+ }
- stmt->state= MY_ST_EXECUTE;
- mysql_free_result(stmt->result);
- stmt->result= (MYSQL_RES *)0;
- stmt->result_buffered= 0;
- stmt->current_row= 0;
+ stmt->state= MYSQL_STMT_EXECUTE_DONE;
+ if (stmt->field_count)
+ {
+ stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
+ stmt->unbuffered_fetch_cancelled= FALSE;
+ stmt->read_row_func= stmt_read_row_unbuffered;
+ }
DBUG_RETURN(0);
}
@@ -2155,6 +2346,16 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
MYSQL_BIND *param, *end;
DBUG_ENTER("mysql_stmt_bind_param");
+ if (!stmt->param_count)
+ {
+ if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
+ {
+ set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+
/* Allocated on prepare */
memcpy((char*) stmt->params, (char*) bind,
sizeof(MYSQL_BIND) * stmt->param_count);
@@ -2166,13 +2367,6 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param->param_number= count++;
param->long_data_used= 0;
- /*
- If param->length is not given, change it to point to buffer_length.
- This way we can always use *param->length to get the length of data
- */
- if (!param->length)
- param->length= &param->buffer_length;
-
/* If param->is_null is not set, then the value can never be NULL */
if (!param->is_null)
param->is_null= &int_is_null_false;
@@ -2239,10 +2433,16 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param->buffer_type, count);
DBUG_RETURN(1);
}
+ /*
+ If param->length is not given, change it to point to buffer_length.
+ This way we can always use *param->length to get the length of data
+ */
+ if (!param->length)
+ param->length= &param->buffer_length;
}
/* We have to send/resendtype information to MySQL */
- stmt->send_types_to_server= 1;
- stmt->param_buffers= 1;
+ stmt->send_types_to_server= TRUE;
+ stmt->bind_param_done= TRUE;
DBUG_RETURN(0);
}
@@ -2276,6 +2476,16 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
DBUG_ASSERT(stmt != 0);
DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld",
param_number, data, length));
+
+ /*
+ We only need to check for stmt->param_count, if it's not null
+ prepare was done.
+ */
+ if (param_number >= stmt->param_count)
+ {
+ set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
param= stmt->params+param_number;
if (param->buffer_type < MYSQL_TYPE_TINY_BLOB ||
@@ -2846,9 +3056,20 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_ENTER("mysql_stmt_bind_result");
DBUG_ASSERT(stmt != 0);
- if (!(bind_count= stmt->field_count) &&
- !(bind_count= alloc_stmt_fields(stmt)))
+ if (!stmt->field_count)
+ {
+ if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
+ {
+ set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
+ }
DBUG_RETURN(0);
+ }
+ bind_count= stmt->field_count;
+
+ /*
+ We only need to check that stmt->field_count - if it is not null
+ stmt->bind was initialized in mysql_stmt_prepare
+ */
memcpy((char*) stmt->bind, (char*) bind,
sizeof(MYSQL_BIND)*bind_count);
@@ -2929,7 +3150,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_RETURN(1);
}
}
- stmt->res_buffers= 1;
+ stmt->bind_result_done= TRUE;
DBUG_RETURN(0);
}
@@ -2943,9 +3164,18 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
MYSQL_BIND *bind, *end;
MYSQL_FIELD *field, *field_end;
uchar *null_ptr, bit;
+ /*
+ Precondition: if stmt->field_count is zero or row is NULL, read_row_*
+ function must return no data.
+ */
+ DBUG_ASSERT(stmt->field_count);
+ DBUG_ASSERT(row);
- if (!row || !stmt->res_buffers)
+ if (!stmt->bind_result_done)
+ {
+ /* If output parameters were not bound we should just return success */
return 0;
+ }
null_ptr= row;
row+= (stmt->field_count+9)/8; /* skip null bits */
@@ -2994,57 +3224,22 @@ int cli_unbuffered_fetch(MYSQL *mysql, char **row)
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
{
- MYSQL *mysql= stmt->mysql;
+ int rc;
uchar *row;
DBUG_ENTER("mysql_stmt_fetch");
- stmt->last_fetched_column= 0; /* reset */
- if (stmt->result_buffered) /* buffered */
+ if ((rc= (*stmt->read_row_func)(stmt, &row)) ||
+ (rc= stmt_fetch_row(stmt, row)))
{
- MYSQL_RES *res;
-
- if (!(res= stmt->result))
- goto no_data;
-
- if (!res->data_cursor)
- {
- stmt->current_row= 0;
- goto no_data;
- }
- row= (uchar *)res->data_cursor->data;
- res->data_cursor= res->data_cursor->next;
+ stmt->state= MYSQL_STMT_PREPARE_DONE; /* XXX: this is buggy */
+ stmt->read_row_func= stmt_read_row_no_data;
}
- else /* un-buffered */
+ else
{
- if (mysql->status != MYSQL_STATUS_GET_RESULT)
- {
- if (!stmt->field_count)
- goto no_data;
-
- set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
- DBUG_RETURN(1);
- }
-
- if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) &row))
- {
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
- DBUG_RETURN(1);
- }
- if (!row)
- {
- mysql->status= MYSQL_STATUS_READY;
- stmt->current_row= 0;
- goto no_data;
- }
+ /* This is to know in mysql_stmt_fetch_column that data was fetched */
+ stmt->state= MYSQL_STMT_FETCH_DONE;
}
-
- stmt->current_row= row;
- DBUG_RETURN(stmt_fetch_row(stmt, row));
-
-no_data:
- DBUG_PRINT("info", ("end of data"));
- DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
+ DBUG_RETURN(rc);
}
@@ -3065,13 +3260,22 @@ no_data:
*/
int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
- uint column, ulong offset)
+ uint column, ulong offset)
{
MYSQL_BIND *param= stmt->bind+column;
DBUG_ENTER("mysql_stmt_fetch_column");
- if (!stmt->current_row)
- goto no_data;
+ if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
+ {
+ set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate);
+ return 1;
+ }
+ if (column >= stmt->field_count)
+ {
+ set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+
if (param->null_field)
{
@@ -3092,10 +3296,6 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
fetch_results(bind, field, &row);
}
DBUG_RETURN(0);
-
-no_data:
- DBUG_PRINT("info", ("end of data"));
- DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
}
@@ -3111,7 +3311,7 @@ MYSQL_DATA *cli_read_binary_rows(MYSQL_STMT *stmt)
MYSQL_DATA *result;
MYSQL_ROWS *cur, **prev_ptr;
NET *net = &mysql->net;
- DBUG_ENTER("read_binary_rows");
+ DBUG_ENTER("cli_read_binary_rows");
mysql= mysql->last_used_con;
if ((pkt_len= net_safe_read(mysql)) == packet_error)
@@ -3181,33 +3381,37 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
if (!stmt->field_count)
DBUG_RETURN(0);
- if (mysql->status != MYSQL_STATUS_GET_RESULT)
+ if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE ||
+ mysql->status != MYSQL_STATUS_GET_RESULT)
{
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1);
}
- mysql->status= MYSQL_STATUS_READY; /* server is ready */
- if (!(result= (MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
- sizeof(ulong) *
- stmt->field_count),
+ if (!(result= (MYSQL_RES*) my_malloc(sizeof(MYSQL_RES),
MYF(MY_WME | MY_ZEROFILL))))
{
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
DBUG_RETURN(1);
}
result->methods= mysql->methods;
- stmt->result_buffered= 1;
- if (!(result->data= (*stmt->mysql->methods->read_binary_rows)(stmt)))
+ if ((result->data= (*mysql->methods->read_binary_rows)(stmt)))
+ {
+ result->row_count= result->data->rows;
+ result->data_cursor= result->data->data;
+ }
+ else if (stmt->last_errno)
{
my_free((gptr) result,MYF(0));
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
- mysql->affected_rows= result->row_count= result->data->rows;
- stmt->affected_rows= result->row_count;
- result->data_cursor= result->data->data;
+ mysql->affected_rows= stmt->affected_rows= result->row_count;
result->fields= stmt->fields;
result->field_count= stmt->field_count;
+ /* The rest of MYSQL_RES members were bzeroed inside my_malloc */
stmt->result= result;
+ stmt->read_row_func= stmt_read_row_buffered;
+ mysql->unbuffered_fetch_owner= 0; /* set in stmt_execute */
+ mysql->status= MYSQL_STATUS_READY; /* server is ready */
DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */
}
@@ -3292,6 +3496,40 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
DBUG_RETURN(0);
}
+my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
+{
+ DBUG_ENTER("mysql_stmt_free_result");
+
+ DBUG_ASSERT(stmt != 0);
+
+ if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
+ {
+ MYSQL *mysql= stmt->mysql;
+
+ if (stmt->result)
+ {
+ /* Result buffered */
+ mysql_free_result(stmt->result);
+ stmt->result= 0;
+ }
+ else if (mysql && stmt->field_count
+ && (int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
+ {
+ if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ /* There is a result set and it belongs to this statement */
+ flush_use_result(mysql);
+ mysql->status= MYSQL_STATUS_READY;
+ }
+ }
+ stmt->state= MYSQL_STMT_PREPARE_DONE;
+ stmt->read_row_func= stmt_read_row_no_data;
+ }
+ DBUG_RETURN(0);
+}
+
/********************************************************************
statement error handling and close
*********************************************************************/
@@ -3300,82 +3538,55 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
Close the statement handle by freeing all alloced resources
SYNOPSIS
- mysql_stmt_free_result()
+ mysql_stmt_close()
stmt Statement handle
- skip_list Flag to indicate delete from list or not
+
RETURN VALUES
0 ok
1 error
*/
-my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
-{
- MYSQL *mysql;
- DBUG_ENTER("mysql_stmt_free_result");
-
- DBUG_ASSERT(stmt != 0);
-
- mysql= stmt->mysql;
- if (mysql->status != MYSQL_STATUS_READY)
- {
- /* Clear the current execution status */
- DBUG_PRINT("warning",("Not all packets read, clearing them"));
- for (;;)
- {
- ulong pkt_len;
- if ((pkt_len= net_safe_read(mysql)) == packet_error)
- break;
- if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
- break;
- }
- mysql->status= MYSQL_STATUS_READY;
- }
- mysql_free_result(stmt->result);
- stmt->result= 0;
- stmt->result_buffered= 0;
- stmt->current_row= 0;
- DBUG_RETURN(0);
-}
-
-
-my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_free)
+my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
{
- MYSQL *mysql;
- DBUG_ENTER("stmt_close");
+ MYSQL *mysql= stmt->mysql;
+ int rc= 0;
+ DBUG_ENTER("mysql_stmt_close");
- DBUG_ASSERT(stmt != 0);
-
- if (!(mysql= stmt->mysql))
- {
- if (!skip_free)
- my_free((gptr) stmt, MYF(MY_WME));
- DBUG_RETURN(0);
- }
- mysql_stmt_free_result(stmt);
- if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE)
+ mysql_free_result(stmt->result); /* if result is buffered */
+ free_root(&stmt->mem_root, MYF(0));
+
+ if (mysql)
{
- char buff[4];
- int4store(buff, stmt->stmt_id);
- if (skip_free || simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
+ mysql->stmts= list_delete(mysql->stmts, &stmt->list);
+ if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
- stmt->mysql= NULL; /* connection isn't valid anymore */
- DBUG_RETURN(1);
+ char buff[4];
+
+ if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ /*
+ Flush result set of the connection. If it does not belong
+ to this statement, set a warning.
+ */
+ flush_use_result(mysql);
+ if (mysql->unbuffered_fetch_owner)
+ *mysql->unbuffered_fetch_owner= TRUE;
+ mysql->status= MYSQL_STATUS_READY;
+ }
+ int4store(buff, stmt->stmt_id);
+ if ((rc= simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1)))
+ {
+ set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
+ mysql->net.sqlstate);
+ }
}
}
- stmt->field_count= 0;
- free_root(&stmt->mem_root, MYF(0));
- mysql->stmts= list_delete(mysql->stmts, &stmt->list);
- mysql->status= MYSQL_STATUS_READY;
- my_free((gptr) stmt, MYF(MY_WME));
- DBUG_RETURN(0);
-}
+ my_free((gptr) stmt, MYF(MY_WME));
-my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
-{
- return stmt_close(stmt, 0);
+ DBUG_RETURN(test(rc));
}
/*
@@ -3388,6 +3599,10 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
MYSQL *mysql;
DBUG_ENTER("mysql_stmt_reset");
DBUG_ASSERT(stmt != 0);
+
+ /* If statement hasnt been prepared there is nothing to reset */
+ if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
+ DBUG_RETURN(0);
mysql= stmt->mysql->last_used_con;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index b65c8b284b3..c3043854063 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -459,16 +459,16 @@ drop table t1, t2;
create table t1(cenum enum('a'), cset set('b'));
create table t2(cenum enum('a','a'), cset set('b','b'));
Warnings:
-Error 1291 Column 'cenum' has duplicated value 'a' in ENUM
-Error 1291 Column 'cset' has duplicated value 'b' in SET
+Note 1291 Column 'cenum' has duplicated value 'a' in ENUM
+Note 1291 Column 'cset' has duplicated value 'b' in SET
create table t3(cenum enum('a','A','a','c','c'), cset set('b','B','b','d','d'));
Warnings:
-Error 1291 Column 'cenum' has duplicated value 'a' in ENUM
-Error 1291 Column 'cenum' has duplicated value 'A' in ENUM
-Error 1291 Column 'cenum' has duplicated value 'c' in ENUM
-Error 1291 Column 'cset' has duplicated value 'b' in SET
-Error 1291 Column 'cset' has duplicated value 'B' in SET
-Error 1291 Column 'cset' has duplicated value 'd' in SET
+Note 1291 Column 'cenum' has duplicated value 'a' in ENUM
+Note 1291 Column 'cenum' has duplicated value 'A' in ENUM
+Note 1291 Column 'cenum' has duplicated value 'c' in ENUM
+Note 1291 Column 'cset' has duplicated value 'b' in SET
+Note 1291 Column 'cset' has duplicated value 'B' in SET
+Note 1291 Column 'cset' has duplicated value 'd' in SET
drop table t1, t2, t3;
create database test_$1;
use test_$1;
diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result
index 165a8d7011c..f1582707cf5 100644
--- a/mysql-test/r/date_formats.result
+++ b/mysql-test/r/date_formats.result
@@ -78,11 +78,11 @@ select str_to_date(concat('15-01-2001',' 2:59:58.999'),
concat('%d-%m-%Y',' ','%H:%i:%s.%f'));
str_to_date(concat('15-01-2001',' 2:59:58.999'),
concat('%d-%m-%Y',' ','%H:%i:%s.%f'))
-2001-01-15 02:59:58.000999
+2001-01-15 02:59:58.999000
create table t1 (date char(30), format char(30) not null);
insert into t1 values
('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'),
-('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'),
+('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S.%#'),
('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'),
('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'),
('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'),
@@ -106,16 +106,16 @@ insert into t1 values
select date,format,str_to_date(date, format) as str_to_date from t1;
date format str_to_date
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
-2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
-2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
-2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
10:20:10 %H:%i:%s 0000-00-00 10:20:10
10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
-10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
15 September 2001 %d %M %Y 2001-09-15 00:00:00
15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00
@@ -130,16 +130,16 @@ Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
select date,format,concat('',str_to_date(date, format)) as con from t1;
date format con
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
-2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
-2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
-2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
10:20:10 %H:%i:%s 0000-00-00 10:20:10
10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
-10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
15 September 2001 %d %M %Y 2001-09-15 00:00:00
15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00
@@ -154,16 +154,16 @@ Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1;
date format datetime
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
-2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
-2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
-2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
10:20:10 %H:%i:%s 0000-00-00 10:20:10
10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
-10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
15 September 2001 %d %M %Y 2001-09-15 00:00:00
15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00
@@ -178,7 +178,7 @@ Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
select date,format,DATE(str_to_date(date, format)) as date2 from t1;
date format date2
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02
2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02
2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02
@@ -202,16 +202,16 @@ Thursday 53 1998 %W %u %Y 1998-12-31
select date,format,TIME(str_to_date(date, format)) as time from t1;
date format time
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12
-2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345
-2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345
-2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.123450
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.123450
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.123450
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12
10:20:10 %H:%i:%s 10:20:10
10:20:10 %h:%i:%s.%f 10:20:10
10:20:10AM %h:%i:%s%p 10:20:10
-10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044
+10:20:10.44AM %h:%i:%s.%f%p 10:20:10.440000
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58
15 September 2001 %d %M %Y 00:00:00
15 SEPTEMB 2001 %d %M %Y 00:00:00
@@ -226,16 +226,16 @@ Thursday 53 1998 %W %u %Y 00:00:00
select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1;
date format time2
2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12
-03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 08:11:02
2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12
-2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345
-2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345
-2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.123450
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.123450
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.123450
2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12
10:20:10 %H:%i:%s 10:20:10
10:20:10 %h:%i:%s.%f 10:20:10
10:20:10AM %h:%i:%s%p 10:20:10
-10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044
+10:20:10.44AM %h:%i:%s.%f%p 10:20:10.440000
15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58
15 September 2001 %d %M %Y 00:00:00
15 SEPTEMB 2001 %d %M %Y 00:00:00
@@ -302,11 +302,15 @@ date format str_to_date
10:20:10AM %h:%i:%s 0000-00-00 10:20:10
2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12
03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12
+Warnings:
+Note 1292 Truncated wrong string value: '10:20:10AM'
select date,format,concat(str_to_date(date, format),'') as con from t1;
date format con
10:20:10AM %h:%i:%s 0000-00-00 10:20:10
2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12
03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12
+Warnings:
+Note 1292 Truncated wrong string value: '10:20:10AM'
drop table t1;
select get_format(DATE, 'USA') as a;
a
@@ -335,3 +339,56 @@ date_format(d,"%d")
14
14
drop table t1;
+select str_to_date("2003-....01ABCD-02 10:11:12.0012", "%Y-%.%m%@-%d %H:%i:%S.%f") as a;
+a
+2003-01-02 10:11:12.001200
+create table t1 select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
+str_to_date("10:11:12.0012", "%H:%i:%S.%f") as f2,
+str_to_date("2003-01-02", "%Y-%m-%d") as f3,
+str_to_date("02", "%d") as f4, str_to_date("02 10", "%d %H") as f5;
+describe t1;
+Field Type Null Key Default Extra
+f1 datetime YES NULL
+f2 time YES NULL
+f3 date YES NULL
+f4 date YES NULL
+f5 time YES NULL
+select * from t1;
+f1 f2 f3 f4 f5
+2003-01-02 10:11:12 10:11:12 2003-01-02 0000-00-02 58:00:00
+drop table t1;
+create table t1 select "02 10" as a, "%d %H" as b;
+select str_to_date(a,b) from t1;
+str_to_date(a,b)
+0000-00-02 10:00:00
+create table t2 select str_to_date(a,b) from t1;
+describe t2;
+Field Type Null Key Default Extra
+str_to_date(a,b) char(29) YES NULL
+select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
+str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2,
+str_to_date("2003-01-02", "%Y-%m-%d") as f3,
+str_to_date("02 10:11:12", "%d %H:%i:%S.%f") as f4,
+str_to_date("02 10:11:12", "%d %H:%i:%S") as f5,
+str_to_date("02 10", "%d %f") as f6;
+f1 f2 f3 f4 f5 f6
+2003-01-02 10:11:12.001200 2003-01-02 10:11:12 2003-01-02 58:11:12 58:11:12 48:00:00.100000
+Warnings:
+Note 1292 Truncated wrong datetime value: '2003-01-02 10:11:12.0012'
+drop table t1, t2;
+select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1,
+addtime("-01:01:01.01 GGG", "-23:59:59.1") as f2,
+microsecond("1997-12-31 23:59:59.01XXXX") as f3;
+f1 f2 f3
+2003-01-02 10:11:12.001200 -25:01:00.110000 10000
+Warnings:
+Note 1292 Truncated wrong datetime value: '2003-01-02 10:11:12.0012ABCD'
+Note 1292 Truncated wrong time value: '-01:01:01.01 GG'
+Note 1292 Truncated wrong datetime value: '1997-12-31 23:59:59.01XXXX'
+select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1,
+str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2;
+f1 f2
+2003-04-05 2003-04-05 10:11:12.101010
+Warnings:
+Note 1292 Truncated wrong date value: '2003-04-05 g'
+Note 1292 Truncated wrong datetime value: '2003-04-05 10:11:12.101010234567'
diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result
index 38bd73bca0f..31868261157 100644
--- a/mysql-test/r/func_sapdb.result
+++ b/mysql-test/r/func_sapdb.result
@@ -198,3 +198,18 @@ NULL NULL
NULL NULL
00:00:00 -24:00:00
drop table t1, test;
+select addtime("-01:01:01.01", "-23:59:59.1") as a;
+a
+-25:01:00.110000
+select microsecond("1997-12-31 23:59:59.01") as a;
+a
+10000
+select microsecond(19971231235959.01) as a;
+a
+10000
+select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a;
+a
+1997-12-31 00:00:10.090000
+select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f");
+str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f")
+2003-01-02 10:11:12.001200
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index eb09a746a1c..86c4b8cf0dc 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -624,6 +624,9 @@ Note 1003 select high_priority md5(_latin1'hello') AS `md5('hello')`,sha(_latin1
SELECT lpad(12345, 5, "#");
lpad(12345, 5, "#")
12345
+SELECT conv(71, 10, 36), conv('1Z', 36, 10);
+conv(71, 10, 36) conv('1Z', 36, 10)
+1Z 71
create table t1 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8;
insert into t1 values (1,'aaaaaaaaaa'), (2,'bbbbbbbbbb');
create table t2 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8;
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 0998f7b8bcf..060a5d0f1bd 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -506,17 +506,32 @@ last_day('2001-01-01 01:01:01') as f5, last_day(NULL),
last_day('2001-02-12');
f1 f2 f3 f4 f5 last_day(NULL) last_day('2001-02-12')
2000-02-29 2002-12-31 NULL 2003-04-30 2001-01-31 NULL 2001-02-28
-create table t1 select last_day('2000-02-05') as a;
+create table t1 select last_day('2000-02-05') as a,
+from_days(to_days("960101")) as b;
describe t1;
Field Type Null Key Default Extra
a date 0000-00-00
+b date YES NULL
select * from t1;
-a
-2000-02-29
+a b
+2000-02-29 1996-01-01
drop table t1;
-select last_day('2000-02-05');
-last_day('2000-02-05')
-2000-02-29
+select last_day('2000-02-05') as a,
+from_days(to_days("960101")) as b;
+a b
+2000-02-29 1996-01-01
+select date_add(last_day("1997-12-1"), INTERVAL 1 DAY);
+date_add(last_day("1997-12-1"), INTERVAL 1 DAY)
+1998-01-01
+select length(last_day("1997-12-1"));
+length(last_day("1997-12-1"))
+10
+select last_day("1997-12-1")+0;
+last_day("1997-12-1")+0
+19971231
+select last_day("1997-12-1")+0.0;
+last_day("1997-12-1")+0.0
+19971231.0
select strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0;
strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0
1
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 03bb588fec9..1b96faa04af 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -1624,3 +1624,9 @@ select 2 in (select * from t1);
1
SET SQL_SELECT_LIMIT=default;
drop table t1;
+create table t1(val varchar(10));
+insert into t1 values ('aaa'), ('bbb'),('eee'),('mmm'),('ppp');
+select count(*) from t1 as w1 where w1.val in (select w2.val from t1 as w2 where w2.val like 'm%') and w1.val in (select w3.val from t1 as w3 where w3.val like 'e%');
+count(*)
+0
+drop table if exists t1;
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 0830179902d..68b56802120 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -25,9 +25,11 @@ t
36:30:31
insert into t1 values("10.22.22"),(1234567),(123456789),(123456789.10),("10 22:22"),("12.45a");
Warnings:
+Note 1292 Truncated wrong time value: '10.22.22'
Warning 1264 Data truncated, out of range for column 't' at row 2
Warning 1264 Data truncated, out of range for column 't' at row 3
Warning 1264 Data truncated, out of range for column 't' at row 4
+Note 1292 Truncated wrong time value: '12.45a'
select * from t1;
t
10:22:33
diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test
index 18af3dfb3db..1fc04cb907b 100644
--- a/mysql-test/t/date_formats.test
+++ b/mysql-test/t/date_formats.test
@@ -124,7 +124,7 @@ select str_to_date(concat('15-01-2001',' 2:59:58.999'),
create table t1 (date char(30), format char(30) not null);
insert into t1 values
('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'),
-('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'),
+('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S.%#'),
('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'),
('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'),
('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'),
@@ -209,3 +209,32 @@ create table t1 (d date);
insert into t1 values ('2004-07-14'),('2005-07-14');
select date_format(d,"%d") from t1 order by 1;
drop table t1;
+
+select str_to_date("2003-....01ABCD-02 10:11:12.0012", "%Y-%.%m%@-%d %H:%i:%S.%f") as a;
+
+
+create table t1 select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
+ str_to_date("10:11:12.0012", "%H:%i:%S.%f") as f2,
+ str_to_date("2003-01-02", "%Y-%m-%d") as f3,
+ str_to_date("02", "%d") as f4, str_to_date("02 10", "%d %H") as f5;
+describe t1;
+select * from t1;
+drop table t1;
+
+create table t1 select "02 10" as a, "%d %H" as b;
+select str_to_date(a,b) from t1;
+create table t2 select str_to_date(a,b) from t1;
+describe t2;
+select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1,
+ str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2,
+ str_to_date("2003-01-02", "%Y-%m-%d") as f3,
+ str_to_date("02 10:11:12", "%d %H:%i:%S.%f") as f4,
+ str_to_date("02 10:11:12", "%d %H:%i:%S") as f5,
+ str_to_date("02 10", "%d %f") as f6;
+drop table t1, t2;
+select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1,
+ addtime("-01:01:01.01 GGG", "-23:59:59.1") as f2,
+ microsecond("1997-12-31 23:59:59.01XXXX") as f3;
+
+select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1,
+ str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2;
diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test
index afd84fe9630..24028437fde 100644
--- a/mysql-test/t/func_sapdb.test
+++ b/mysql-test/t/func_sapdb.test
@@ -97,3 +97,9 @@ SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test;
SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test;
drop table t1, test;
+
+select addtime("-01:01:01.01", "-23:59:59.1") as a;
+select microsecond("1997-12-31 23:59:59.01") as a;
+select microsecond(19971231235959.01) as a;
+select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a;
+select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f");
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index c9ead51c0a6..1e6d279f721 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -361,6 +361,13 @@ explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'moo
SELECT lpad(12345, 5, "#");
+#
+# Bug #2972
+#
+
+SELECT conv(71, 10, 36), conv('1Z', 36, 10);
+
+
#
# Bug #3089
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 06d0ff3fa1d..6417d5448e5 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -249,12 +249,18 @@ select last_day('2000-02-05') as f1, last_day('2002-12-31') as f2,
last_day('2001-01-01 01:01:01') as f5, last_day(NULL),
last_day('2001-02-12');
-create table t1 select last_day('2000-02-05') as a;
+create table t1 select last_day('2000-02-05') as a,
+ from_days(to_days("960101")) as b;
describe t1;
select * from t1;
drop table t1;
-select last_day('2000-02-05');
+select last_day('2000-02-05') as a,
+ from_days(to_days("960101")) as b;
+select date_add(last_day("1997-12-1"), INTERVAL 1 DAY);
+select length(last_day("1997-12-1"));
+select last_day("1997-12-1")+0;
+select last_day("1997-12-1")+0.0;
# Test SAPDB UTC_% functions. This part is TZ dependant (It is supposed that
# TZ variable set to GMT-3
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 1a33890360d..191e12bef5d 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -1066,3 +1066,10 @@ select 2 in (select * from t1);
SET SQL_SELECT_LIMIT=default;
drop table t1;
+#
+# Item_cond fix field
+#
+create table t1(val varchar(10));
+insert into t1 values ('aaa'), ('bbb'),('eee'),('mmm'),('ppp');
+select count(*) from t1 as w1 where w1.val in (select w2.val from t1 as w2 where w2.val like 'm%') and w1.val in (select w3.val from t1 as w3 where w3.val like 'e%');
+drop table if exists t1;
diff --git a/sql-common/client.c b/sql-common/client.c
index 5d2df4a0ddf..6d0da338543 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -712,6 +712,34 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
net->last_errno= errcode;
strmov(net->last_error, ER(errcode));
strmov(net->sqlstate, sqlstate);
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Flush result set sent from server
+*/
+
+void flush_use_result(MYSQL *mysql)
+{
+ /* Clear the current execution status */
+ DBUG_PRINT("warning",("Not all packets read, clearing them"));
+ for (;;)
+ {
+ ulong pkt_len;
+ if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ break;
+ if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
+ {
+ if (protocol_41(mysql))
+ {
+ char *pos= (char*) mysql->net.read_pos;
+ mysql->warning_count=uint2korr(pos); pos+=2;
+ mysql->server_status=uint2korr(pos); pos+=2;
+ }
+ break; /* End of data */
+ }
+ }
}
@@ -752,26 +780,16 @@ mysql_free_result(MYSQL_RES *result)
DBUG_PRINT("enter",("mysql_res: %lx",result));
if (result)
{
- if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
+ MYSQL *mysql= result->handle;
+ if (mysql)
{
- DBUG_PRINT("warning",("Not all rows in set where read; Ignoring rows"));
- for (;;)
+ if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ if (mysql->status == MYSQL_STATUS_USE_RESULT)
{
- ulong pkt_len;
- if ((pkt_len=net_safe_read(result->handle)) == packet_error)
- break;
- if (pkt_len <= 8 && result->handle->net.read_pos[0] == 254)
- {
- if (protocol_41(result->handle))
- {
- char *pos= (char*) result->handle->net.read_pos;
- result->handle->warning_count=uint2korr(pos); pos+=2;
- result->handle->server_status=uint2korr(pos); pos+=2;
- }
- break; /* End of data */
- }
+ flush_use_result(mysql);
+ mysql->status=MYSQL_STATUS_READY;
}
- result->handle->status=MYSQL_STATUS_READY;
}
free_rows(result->data);
if (result->fields)
@@ -2177,12 +2195,13 @@ void STDCALL mysql_close(MYSQL *mysql)
#ifdef MYSQL_CLIENT
if (mysql->stmts)
{
- /* Free any open prepared statements */
- LIST *element, *next_element;
- for (element= mysql->stmts; element; element= next_element)
+ /* Reset connection handle in all prepared statements. */
+ LIST *element;
+ for (element= mysql->stmts; element; element= element->next)
{
- next_element= element->next;
- stmt_close((MYSQL_STMT *)element->data, 1);
+ MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
+ stmt->mysql= 0;
+ /* No need to call list_delete for statement here */
}
mysql->stmts= 0;
}
@@ -2372,9 +2391,10 @@ MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
result->fields= mysql->fields;
result->field_alloc= mysql->field_alloc;
result->field_count= mysql->field_count;
- result->current_field=0;
- result->current_row=0; /* Must do a fetch first */
+ /* The rest of result members is bzeroed in malloc */
mysql->fields=0; /* fields is now in result */
+ /* just in case this was mistakenly called after mysql_stmt_execute() */
+ mysql->unbuffered_fetch_owner= 0;
DBUG_RETURN(result); /* Data fetched */
}
@@ -2423,6 +2443,7 @@ static MYSQL_RES * cli_use_result(MYSQL *mysql)
result->current_row= 0;
mysql->fields=0; /* fields is now in result */
mysql->status=MYSQL_STATUS_USE_RESULT;
+ mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
DBUG_RETURN(result); /* Data is read to be fetched */
}
@@ -2439,19 +2460,30 @@ mysql_fetch_row(MYSQL_RES *res)
{ /* Unbufferred fetch */
if (!res->eof)
{
- if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
+ MYSQL *mysql= res->handle;
+ if (mysql->status != MYSQL_STATUS_USE_RESULT)
{
- res->row_count++;
- DBUG_RETURN(res->current_row=res->row);
+ set_mysql_error(mysql,
+ res->unbuffered_fetch_cancelled ?
+ CR_FETCH_CANCELLED : CR_COMMANDS_OUT_OF_SYNC,
+ unknown_sqlstate);
}
- else
+ else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
{
- DBUG_PRINT("info",("end of data"));
- res->eof=1;
- res->handle->status=MYSQL_STATUS_READY;
- /* Don't clear handle in mysql_free_results */
- res->handle=0;
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
}
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ mysql->status=MYSQL_STATUS_READY;
+ /*
+ Reset only if owner points to us: there is a chance that somebody
+ started new query after mysql_stmt_close():
+ */
+ if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ /* Don't clear handle in mysql_free_result */
+ res->handle=0;
}
DBUG_RETURN((MYSQL_ROW) NULL);
}
diff --git a/sql/item.cc b/sql/item.cc
index 5aaeffff5d2..45cd85d1775 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -517,7 +517,33 @@ String *Item_null::val_str(String *str)
{ null_value=1; return 0;}
-/* Item_param related */
+/*********************** Item_param related ******************************/
+
+/*
+ Default function of Item_param::set_param_func, so in case
+ of malformed packet the server won't SIGSEGV
+*/
+
+static void
+default_set_param_func(Item_param *param,
+ uchar **pos __attribute__((unused)),
+ ulong len __attribute__((unused)))
+{
+ param->set_null();
+}
+
+Item_param::Item_param(unsigned position) :
+ value_is_set(FALSE),
+ item_result_type(STRING_RESULT),
+ item_type(STRING_ITEM),
+ item_is_time(FALSE),
+ long_data_supplied(FALSE),
+ pos_in_query(position),
+ set_param_func(default_set_param_func)
+{
+ name= (char*) "?";
+}
+
void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
@@ -928,6 +954,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(char *)field_name);
if (!rf)
return 1;
+ /*
+ rf is Item_ref => never substitute other items (in this case)
+ during fix_fields() => we can use rf after fix_fields()
+ */
if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
return 1;
@@ -946,6 +976,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(char *)field_name);
if (!rf)
return 1;
+ /*
+ rf is Item_ref => never substitute other items (in this case)
+ during fix_fields() => we can use rf after fix_fields()
+ */
return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
}
}
@@ -1658,16 +1692,15 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const
}
-bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
+bool Item_default_value::fix_fields(THD *thd,
+ struct st_table_list *table_list,
+ Item **items)
{
if (!arg)
- return false;
- bool res= arg->fix_fields(thd, table_list, items);
- if (res)
- return res;
- /* arg->type() can be only REF_ITEM or FIELD_ITEM for it defined as
- simple_ident in sql_yacc.yy
- */
+ return 0;
+ if (arg->fix_fields(thd, table_list, &arg))
+ return 1;
+
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
@@ -1711,13 +1744,9 @@ bool Item_insert_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
- bool res= arg->fix_fields(thd, table_list, items);
- if (res)
- return res;
- /*
- arg->type() can be only REF_ITEM or FIELD_ITEM as arg is
- a simple_ident in sql_yacc.yy
- */
+ if (arg->fix_fields(thd, table_list, &arg))
+ return 1;
+
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
diff --git a/sql/item.h b/sql/item.h
index 727132916f0..832fc775016 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -348,16 +348,7 @@ public:
bool long_data_supplied;
uint pos_in_query;
- Item_param(uint position)
- {
- name= (char*) "?";
- pos_in_query= position;
- item_type= STRING_ITEM;
- item_result_type = STRING_RESULT;
- item_is_time= false;
- long_data_supplied= false;
- value_is_set= 0;
- }
+ Item_param(uint position);
enum Type type() const { return item_type; }
double val();
longlong val_int();
@@ -374,11 +365,14 @@ public:
void set_time(TIME *tm, timestamp_type type);
bool get_time(TIME *tm);
void reset() {}
-#ifndef EMBEDDED_LIBRARY
- void (*set_param_func)(Item_param *param, uchar **pos);
-#else
- void (*set_param_func)(Item_param *param, uchar **pos, ulong data_len);
-#endif
+ /*
+ Assign placeholder value from bind data.
+ Note, that 'len' has different semantics in embedded library (as we
+ don't need to check that packet is not broken there). See
+ sql_prepare.cc for details.
+ */
+ void (*set_param_func)(Item_param *param, uchar **pos, ulong len);
+
enum Item_result result_type () const
{ return item_result_type; }
String *query_val_str(String *str);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index f0bc73e9501..b56ad6febd4 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1775,8 +1775,11 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
if (abort_on_null)
item->top_level_item();
+
+ // item can be substituted in fix_fields
if ((!item->fixed &&
- item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
+ item->fix_fields(thd, tables, li.ref())) ||
+ (item= *li.ref())->check_cols(1))
return 1; /* purecov: inspected */
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0327204dbfd..878c4d2ea5f 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1469,8 +1469,11 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
+ if ((*arg)->fix_fields(thd, tables, arg))
+ return 1;
+ // we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
- if (item->fix_fields(thd, tables, arg) || item->check_cols(1))
+ if (item->check_cols(1))
return 1;
/*
TODO: We should think about this. It is not always
@@ -1728,7 +1731,7 @@ bool udf_handler::get_arguments() { return 0; }
pthread_mutex_t LOCK_user_locks;
static HASH hash_user_locks;
-class ULL
+class User_level_lock
{
char *key;
uint key_length;
@@ -1740,7 +1743,7 @@ public:
pthread_t thread;
ulong thread_id;
- ULL(const char *key_arg,uint length, ulong id)
+ User_level_lock(const char *key_arg,uint length, ulong id)
:key_length(length),count(1),locked(1), thread_id(id)
{
key=(char*) my_memdup((byte*) key_arg,length,MYF(0));
@@ -1754,7 +1757,7 @@ public:
}
}
}
- ~ULL()
+ ~User_level_lock()
{
if (key)
{
@@ -1764,11 +1767,12 @@ public:
pthread_cond_destroy(&cond);
}
inline bool initialized() { return key != 0; }
- friend void item_user_lock_release(ULL *ull);
- friend char *ull_get_key(const ULL *ull,uint *length,my_bool not_used);
+ friend void item_user_lock_release(User_level_lock *ull);
+ friend char *ull_get_key(const User_level_lock *ull, uint *length,
+ my_bool not_used);
};
-char *ull_get_key(const ULL *ull,uint *length,
+char *ull_get_key(const User_level_lock *ull, uint *length,
my_bool not_used __attribute__((unused)))
{
*length=(uint) ull->key_length;
@@ -1796,7 +1800,7 @@ void item_user_lock_free(void)
}
}
-void item_user_lock_release(ULL *ull)
+void item_user_lock_release(User_level_lock *ull)
{
ull->locked=0;
if (mysql_bin_log.is_open())
@@ -1852,7 +1856,7 @@ longlong Item_master_pos_wait::val_int()
void debug_sync_point(const char* lock_name, uint lock_timeout)
{
THD* thd=current_thd;
- ULL* ull;
+ User_level_lock* ull;
struct timespec abstime;
int lock_name_len,error=0;
lock_name_len=strlen(lock_name);
@@ -1870,7 +1874,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
this case, we will not be waiting, but rather, just waste CPU and
memory on the whole deal
*/
- if (!(ull= ((ULL*) hash_search(&hash_user_locks,lock_name,
+ if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks, lock_name,
lock_name_len))))
{
pthread_mutex_unlock(&LOCK_user_locks);
@@ -1931,7 +1935,7 @@ longlong Item_func_get_lock::val_int()
longlong timeout=args[1]->val_int();
struct timespec abstime;
THD *thd=current_thd;
- ULL *ull;
+ User_level_lock *ull;
int error=0;
pthread_mutex_lock(&LOCK_user_locks);
@@ -1950,10 +1954,11 @@ longlong Item_func_get_lock::val_int()
thd->ull=0;
}
- if (!(ull= ((ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),
- res->length()))))
+ if (!(ull= ((User_level_lock *) hash_search(&hash_user_locks,
+ (byte*) res->ptr(),
+ res->length()))))
{
- ull=new ULL(res->ptr(),res->length(), thd->thread_id);
+ ull=new User_level_lock(res->ptr(),res->length(), thd->thread_id);
if (!ull || !ull->initialized())
{
delete ull;
@@ -2022,7 +2027,7 @@ longlong Item_func_get_lock::val_int()
longlong Item_func_release_lock::val_int()
{
String *res=args[0]->val_str(&value);
- ULL *ull;
+ User_level_lock *ull;
longlong result;
if (!res || !res->length())
{
@@ -2033,8 +2038,9 @@ longlong Item_func_release_lock::val_int()
result=0;
pthread_mutex_lock(&LOCK_user_locks);
- if (!(ull= ((ULL*) hash_search(&hash_user_locks,(const byte*) res->ptr(),
- res->length()))))
+ if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
+ (const byte*) res->ptr(),
+ res->length()))))
{
null_value=1;
}
@@ -3041,7 +3047,7 @@ longlong Item_func_is_free_lock::val_int()
{
String *res=args[0]->val_str(&value);
THD *thd=current_thd;
- ULL *ull;
+ User_level_lock *ull;
null_value=0;
if (!res || !res->length())
@@ -3051,7 +3057,7 @@ longlong Item_func_is_free_lock::val_int()
}
pthread_mutex_lock(&LOCK_user_locks);
- ull= (ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
@@ -3063,14 +3069,14 @@ longlong Item_func_is_used_lock::val_int()
{
String *res=args[0]->val_str(&value);
THD *thd=current_thd;
- ULL *ull;
+ User_level_lock *ull;
null_value=1;
if (!res || !res->length())
return 0;
pthread_mutex_lock(&LOCK_user_locks);
- ull= (ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
diff --git a/sql/item_func.h b/sql/item_func.h
index 3890e7c6de5..8fbe5a124da 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -864,9 +864,9 @@ public:
** User level locks
*/
-class ULL;
+class User_level_lock;
void item_user_lock_init(void);
-void item_user_lock_release(ULL *ull);
+void item_user_lock_release(User_level_lock *ull);
void item_user_lock_free(void);
class Item_func_get_lock :public Item_int_func
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 7f847bd1d4e..2b0cd38e3c1 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -62,19 +62,21 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
{
if ((*arg)->fix_fields(thd, tabl, arg))
return 1;
- used_tables_cache |= (*arg)->used_tables();
- if (const_item_cache&= (*arg)->const_item() && !with_null)
+ // we can't assign 'item' before, because fix_fields() can change arg
+ Item *item= *arg;
+ used_tables_cache |= item->used_tables();
+ if (const_item_cache&= item->const_item() && !with_null)
{
- if ((*arg)->cols() > 1)
- with_null|= (*arg)->null_inside();
+ if (item->cols() > 1)
+ with_null|= item->null_inside();
else
{
- (*arg)->val_int();
- with_null|= (*arg)->null_value;
+ item->val_int();
+ with_null|= item->null_value;
}
}
- maybe_null|= (*arg)->maybe_null;
- with_sum_func= with_sum_func || (*arg)->with_sum_func;
+ maybe_null|= item->maybe_null;
+ with_sum_func= with_sum_func || item->with_sum_func;
}
return 0;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 3c8689e1588..2833e1ca016 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2721,7 +2721,7 @@ String *Item_func_uuid::val_str(String *str)
{
ulong tmp=sql_rnd_with_mutex();
uchar mac[6];
- unsigned int i;
+ int i;
if (my_gethwaddr(mac))
{
/*
@@ -2731,7 +2731,7 @@ String *Item_func_uuid::val_str(String *str)
randominit() here
*/
randominit(&uuid_rand, tmp + (ulong)current_thd, tmp + query_id);
- for (i=0; i < sizeof(mac); i++)
+ for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
}
s=clock_seq_and_node_str+sizeof(clock_seq_and_node_str)-1;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 372f086d464..c5fdd79279d 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -650,8 +650,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*select_lex->ref_pointer_array= item;
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
-
- if (item->fix_fields(thd, join->tables_list, &item))
+
+ if (item->fix_fields(thd, join->tables_list,
+ select_lex->item_list.head_ref()))
goto err;
subs= new Item_singlerow_subselect(select_lex);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 879c5f99ebd..77a910ae5d6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -191,17 +191,21 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- Item *item=args[0];
+ Item *item= args[0];
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
return 1;
}
thd->allow_sum_func=0; // No included group funcs
+
+ // 'item' can be changed during fix_fields
if (!item->fixed &&
- item->fix_fields(thd, tables, args) || item->check_cols(1))
+ item->fix_fields(thd, tables, args) ||
+ (item= args[0])->check_cols(1))
return 1;
- hybrid_type=item->result_type();
+
+ hybrid_type= item->result_type();
if (hybrid_type == INT_RESULT)
{
cmp_charset= &my_charset_bin;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 32fbe192d8f..d0674411fcf 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -48,11 +48,6 @@ TYPELIB day_names_typelib=
{ array_elements(day_names)-1,"", day_names};
-enum date_time_format_types
-{
- TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
-};
-
/*
OPTIMIZATION TODO:
- Replace the switch with a function that should be called for each
@@ -128,6 +123,9 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
val String to decode
length Length of string
l_time Store result here
+ cached_timestamp_type
+ It uses to get an appropriate warning
+ in the case when the value is truncated.
RETURN
0 ok
@@ -135,7 +133,8 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
*/
static bool extract_date_time(DATE_TIME_FORMAT *format,
- const char *val, uint length, TIME *l_time)
+ const char *val, uint length, TIME *l_time,
+ timestamp_type cached_timestamp_type)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
@@ -143,9 +142,11 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
int error= 0;
bool usa_time= 0;
bool sunday_first= 0;
+ int frac_part;
+ const char *val_begin= val;
const char *val_end= val + length;
const char *ptr= format->format.str;
- const char *end= ptr+ format->format.length;
+ const char *end= ptr + format->format.length;
DBUG_ENTER("extract_date_time");
bzero((char*) l_time, sizeof(*l_time));
@@ -235,7 +236,12 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
/* Second part */
case 'f':
tmp= (char*) val_end;
+ if (tmp - val > 6)
+ tmp= (char*) val + 6;
l_time->second_part= (int) my_strtoll10(val, &tmp, &error);
+ frac_part= 6 - (tmp - val);
+ if (frac_part > 0)
+ l_time->second_part*= (ulong) log_10_int[frac_part];
val= tmp;
break;
@@ -251,6 +257,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
(const uchar *) val, 2,
(const uchar *) "AM", 2))
goto err;
+ val+= 2;
break;
/* Exotic things */
@@ -281,6 +288,18 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
val= tmp;
break;
+ case '.':
+ while (my_ispunct(cs, *val) && val != val_end)
+ val++;
+ break;
+ case '@':
+ while (my_isalpha(cs, *val) && val != val_end)
+ val++;
+ break;
+ case '#':
+ while (my_isdigit(cs, *val) && val != val_end)
+ val++;
+ break;
default:
goto err;
}
@@ -348,6 +367,18 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
l_time->minute > 59 || l_time->second > 59)
goto err;
+ if (val != val_end)
+ {
+ do
+ {
+ if (!my_isspace(&my_charset_latin1,*val))
+ {
+ make_truncated_value_warning(current_thd, val_begin, length,
+ cached_timestamp_type);
+ break;
+ }
+ } while (++val != val_end);
+ }
DBUG_RETURN(0);
err:
@@ -584,16 +615,27 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
/*
-** Get a array of positive numbers from a string object.
-** Each number is separated by 1 non digit character
-** Return error if there is too many numbers.
-** If there is too few numbers, assume that the numbers are left out
-** from the high end. This allows one to give:
-** DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
+ Get a array of positive numbers from a string object.
+ Each number is separated by 1 non digit character
+ Return error if there is too many numbers.
+ If there is too few numbers, assume that the numbers are left out
+ from the high end. This allows one to give:
+ DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
+
+ SYNOPSIS
+ str: string value
+ length: length of str
+ cs: charset of str
+ values: array of results
+ count: count of elements in result array
+ transform_msec: if value is true we suppose
+ that the last part of string value is microseconds
+ and we should transform value to six digit value.
+ For example, '1.1' -> '1.100000'
*/
bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
- uint count, long *values)
+ uint count, long *values, bool transform_msec)
{
const char *end=str+length;
uint i;
@@ -603,8 +645,15 @@ bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
for (i=0 ; i < count ; i++)
{
long value;
+ const char *start= str;
for (value=0; str != end && my_isdigit(cs,*str) ; str++)
value=value*10L + (long) (*str - '0');
+ if (transform_msec && i == count - 1) // microseconds always last
+ {
+ long msec_length= 6 - (str - start);
+ if (msec_length > 0)
+ value*= (long) log_10_int[msec_length];
+ }
values[i]= value;
while (str != end && !my_isdigit(cs,*str))
str++;
@@ -925,19 +974,19 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->second=value;
break;
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
- if (get_interval_info(str,length,cs,2,array))
+ if (get_interval_info(str,length,cs,2,array,0))
return (1);
interval->year=array[0];
interval->month=array[1];
break;
case INTERVAL_DAY_HOUR:
- if (get_interval_info(str,length,cs,2,array))
+ if (get_interval_info(str,length,cs,2,array,0))
return (1);
interval->day=array[0];
interval->hour=array[1];
break;
case INTERVAL_DAY_MICROSECOND:
- if (get_interval_info(str,length,cs,5,array))
+ if (get_interval_info(str,length,cs,5,array,1))
return (1);
interval->day=array[0];
interval->hour=array[1];
@@ -946,14 +995,14 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->second_part=array[4];
break;
case INTERVAL_DAY_MINUTE:
- if (get_interval_info(str,length,cs,3,array))
+ if (get_interval_info(str,length,cs,3,array,0))
return (1);
interval->day=array[0];
interval->hour=array[1];
interval->minute=array[2];
break;
case INTERVAL_DAY_SECOND:
- if (get_interval_info(str,length,cs,4,array))
+ if (get_interval_info(str,length,cs,4,array,0))
return (1);
interval->day=array[0];
interval->hour=array[1];
@@ -961,7 +1010,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->second=array[3];
break;
case INTERVAL_HOUR_MICROSECOND:
- if (get_interval_info(str,length,cs,4,array))
+ if (get_interval_info(str,length,cs,4,array,1))
return (1);
interval->hour=array[0];
interval->minute=array[1];
@@ -969,33 +1018,33 @@ static bool get_interval_value(Item *args,interval_type int_type,
interval->second_part=array[3];
break;
case INTERVAL_HOUR_MINUTE:
- if (get_interval_info(str,length,cs,2,array))
+ if (get_interval_info(str,length,cs,2,array,0))
return (1);
interval->hour=array[0];
interval->minute=array[1];
break;
case INTERVAL_HOUR_SECOND:
- if (get_interval_info(str,length,cs,3,array))
+ if (get_interval_info(str,length,cs,3,array,0))
return (1);
interval->hour=array[0];
interval->minute=array[1];
interval->second=array[2];
break;
case INTERVAL_MINUTE_MICROSECOND:
- if (get_interval_info(str,length,cs,3,array))
+ if (get_interval_info(str,length,cs,3,array,1))
return (1);
interval->minute=array[0];
interval->second=array[1];
interval->second_part=array[2];
break;
case INTERVAL_MINUTE_SECOND:
- if (get_interval_info(str,length,cs,2,array))
+ if (get_interval_info(str,length,cs,2,array,0))
return (1);
interval->minute=array[0];
interval->second=array[1];
break;
case INTERVAL_SECOND_MICROSECOND:
- if (get_interval_info(str,length,cs,2,array))
+ if (get_interval_info(str,length,cs,2,array,1))
return (1);
interval->second=array[0];
interval->second_part=array[1];
@@ -1008,22 +1057,13 @@ static bool get_interval_value(Item *args,interval_type int_type,
String *Item_date::val_str(String *str)
{
TIME ltime;
- ulong value=(ulong) val_int();
- if (null_value)
- return (String*) 0;
-
+ if (get_date(&ltime, TIME_FUZZY_DATE))
+ return (String *) 0;
if (str->alloc(11))
{
null_value= 1;
return (String *) 0;
}
-
- ltime.year= (value/10000L) % 10000;
- ltime.month= (value/100)%100;
- ltime.day= (value%100);
- ltime.neg= 0;
- ltime.time_type=TIMESTAMP_DATE;
-
make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
}
@@ -1032,28 +1072,31 @@ String *Item_date::val_str(String *str)
int Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
- timestamp_type t_type=TIMESTAMP_DATETIME;
if (get_date(&ltime, TIME_FUZZY_DATE))
- {
- if (null_value)
- return set_field_to_null(field);
- t_type=TIMESTAMP_NONE; // Error
- }
+ return set_field_to_null(field);
field->set_notnull();
- field->store_time(&ltime,t_type);
+ field->store_time(&ltime, TIMESTAMP_DATE);
return 0;
}
-longlong Item_func_from_days::val_int()
+longlong Item_date::val_int()
+{
+ TIME ltime;
+ if (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+ return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day);
+}
+
+
+bool Item_func_from_days::get_date(TIME *ltime, uint fuzzy_date)
{
longlong value=args[0]->val_int();
if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
-
- uint year,month,day;
- get_date_from_daynr((long) value,&year,&month,&day);
- return (longlong) (year*10000L+month*100+day);
+ return 1;
+ get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
+ ltime->time_type= TIMESTAMP_DATE;
+ return 0;
}
@@ -1082,6 +1125,16 @@ void Item_func_curdate::fix_length_and_dec()
ltime.time_type=TIMESTAMP_DATE;
}
+String *Item_func_curdate::val_str(String *str)
+{
+ if (str->alloc(11))
+ {
+ null_value= 1;
+ return (String *) 0;
+ }
+ make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
+ return str;
+}
bool Item_func_curdate::get_date(TIME *res,
uint fuzzy_date __attribute__((unused)))
@@ -2311,6 +2364,103 @@ void Item_func_get_format::print(String *str)
}
+/*
+ check_result_type(s, l) returns DATE/TIME type
+ according to format string
+
+ s: DATE/TIME format string
+ l: length of s
+ Result: date_time_format_types value:
+ DATE_TIME_MICROSECOND, DATE_TIME,
+ TIME_MICROSECOND, TIME_ONLY
+
+ We don't process day format's characters('D', 'd', 'e')
+ because day may be a member of all date/time types.
+ If only day format's character and no time part present
+ the result type is MYSQL_TYPE_DATE
+*/
+
+date_time_format_types check_result_type(const char *format, uint length)
+{
+ const char *time_part_frms= "HISThiklrs";
+ const char *date_part_frms= "MUYWabcjmuyw";
+ bool date_part_used= 0, time_part_used= 0, frac_second_used= 0;
+
+ const char *val= format;
+ const char *end= format + length;
+
+ for (; val != end && val != end; val++)
+ {
+ if (*val == '%' && val+1 != end)
+ {
+ val++;
+ if ((frac_second_used= (*val == 'f')) ||
+ (!time_part_used && strchr(time_part_frms, *val)))
+ time_part_used= 1;
+ else if (!date_part_used && strchr(date_part_frms, *val))
+ date_part_used= 1;
+ if (time_part_used && date_part_used && frac_second_used)
+ return DATE_TIME_MICROSECOND;
+ }
+ }
+
+ if (time_part_used)
+ {
+ if (date_part_used)
+ return DATE_TIME;
+ if (frac_second_used)
+ return TIME_MICROSECOND;
+ return TIME_ONLY;
+ }
+ return DATE_ONLY;
+}
+
+
+Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg)
+{
+ if (cached_field_type == MYSQL_TYPE_TIME)
+ return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
+ if (cached_field_type == MYSQL_TYPE_DATE)
+ return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
+ if (cached_field_type == MYSQL_TYPE_DATETIME)
+ return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
+ return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin));
+}
+
+
+void Item_func_str_to_date::fix_length_and_dec()
+{
+ char format_buff[64];
+ String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
+ maybe_null= 1;
+ decimals=0;
+ cached_field_type= MYSQL_TYPE_STRING;
+ max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ cached_timestamp_type= TIMESTAMP_NONE;
+ if ((const_item= args[1]->const_item()))
+ {
+ format= args[1]->val_str(&format_str);
+ cached_format_type= check_result_type(format->ptr(), format->length());
+ switch (cached_format_type) {
+ case DATE_ONLY:
+ cached_timestamp_type= TIMESTAMP_DATE;
+ cached_field_type= MYSQL_TYPE_DATE;
+ max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ break;
+ case TIME_ONLY:
+ case TIME_MICROSECOND:
+ cached_timestamp_type= TIMESTAMP_TIME;
+ cached_field_type= MYSQL_TYPE_TIME;
+ max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ break;
+ default:
+ cached_timestamp_type= TIMESTAMP_DATETIME;
+ cached_field_type= MYSQL_TYPE_DATETIME;
+ break;
+ }
+ }
+}
+
bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
{
DATE_TIME_FORMAT date_time_format;
@@ -2328,8 +2478,18 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
- ltime))
+ ltime, cached_timestamp_type))
goto null_date;
+ if (cached_timestamp_type == TIMESTAMP_TIME && ltime->day)
+ {
+ /*
+ Day part for time type can be nonzero value and so
+ we should add hours from day part to hour part to
+ keep valid time value.
+ */
+ ltime->hour+= ltime->day*24;
+ ltime->day= 0;
+ }
return 0;
null_date:
@@ -2344,29 +2504,22 @@ String *Item_func_str_to_date::val_str(String *str)
if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
return 0;
- /*
- The following DATE_TIME should be done dynamicly based on the
- format string (wen it's a constant). For example, we should only return
- microseconds if there was an %f in the format
- */
- if (!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
+ if (!make_datetime((const_item ? cached_format_type :
+ (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)),
&ltime, str))
return str;
return 0;
}
-String *Item_func_last_day::val_str(String *str)
+bool Item_func_last_day::get_date(TIME *ltime, uint fuzzy_date)
{
- TIME ltime;
- if (!get_arg0_date(&ltime,0))
- {
- uint month_idx= ltime.month-1;
- ltime.day= days_in_month[month_idx];
- if ( month_idx == 1 && calc_days_in_year(ltime.year) == 366)
- ltime.day+= 1;
- if (!make_datetime(DATE_ONLY, &ltime, str))
- return str;
- }
+ if (get_arg0_date(ltime,fuzzy_date))
+ return 1;
+ uint month_idx= ltime->month-1;
+ ltime->day= days_in_month[month_idx];
+ if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
+ ltime->day= 29;
+ ltime->time_type= TIMESTAMP_DATE;
return 0;
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 854a54bbe80..1b044b49fb1 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -21,6 +21,11 @@
#pragma interface /* gcc class implementation */
#endif
+enum date_time_format_types
+{
+ TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
+};
+
class Item_func_period_add :public Item_int_func
{
public:
@@ -318,6 +323,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
String *val_str(String *str);
+ longlong val_int();
double val() { return (double) val_int(); }
const char *func_name() const { return "date"; }
void fix_length_and_dec()
@@ -407,6 +413,7 @@ public:
Item_func_curdate() :Item_date() {}
void set_result_from_tm(struct tm *now);
longlong val_int() { return (value) ; }
+ String *val_str(String *str);
void fix_length_and_dec();
bool get_date(TIME *res, uint fuzzy_date);
virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
@@ -477,8 +484,8 @@ class Item_func_from_days :public Item_date
{
public:
Item_func_from_days(Item *a) :Item_date(a) {}
- longlong val_int();
const char *func_name() const { return "from_days"; }
+ bool get_date(TIME *res, uint fuzzy_date);
};
@@ -806,37 +813,29 @@ public:
};
-class Item_func_str_to_date :public Item_date_func
+class Item_func_str_to_date :public Item_str_func
{
+ enum_field_types cached_field_type;
+ date_time_format_types cached_format_type;
+ timestamp_type cached_timestamp_type;
+ bool const_item;
public:
Item_func_str_to_date(Item *a, Item *b)
- :Item_date_func(a, b)
+ :Item_str_func(a, b)
{}
String *val_str(String *str);
bool get_date(TIME *ltime, uint fuzzy_date);
const char *func_name() const { return "str_to_date"; }
- void fix_length_and_dec()
- {
- maybe_null= 1;
- decimals=0;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- }
+ enum_field_types field_type() const { return cached_field_type; }
+ void fix_length_and_dec();
+ Field *tmp_table_field(TABLE *t_arg);
};
-class Item_func_last_day :public Item_str_func
+
+class Item_func_last_day :public Item_date
{
public:
- Item_func_last_day(Item *a) :Item_str_func(a) {}
- String *val_str(String *str);
+ Item_func_last_day(Item *a) :Item_date(a) {}
const char *func_name() const { return "last_day"; }
- enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- void fix_length_and_dec()
- {
- decimals=0;
- max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- }
- Field *tmp_table_field(TABLE *t_arg)
- {
- return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
- }
+ bool get_date(TIME *res, uint fuzzy_date);
};
diff --git a/sql/lock.cc b/sql/lock.cc
index 29795415720..67a085ff708 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -495,7 +495,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
char key[MAX_DBKEY_LENGTH];
- char *db= table_list->db ? table_list->db : (thd->db ? thd->db : (char*) "");
+ char *db= table_list->db;
uint key_length;
DBUG_ENTER("lock_table_name");
safe_mutex_assert_owner(&LOCK_open);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index a128b5809b2..0bcaff22f0f 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2344,6 +2344,10 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
}
}
Item_func_set_user_var e(user_var_name, it);
+ /*
+ Item_func_set_user_var can't substitute something else on its place =>
+ 0 can be passed as last argument (reference on item)
+ */
e.fix_fields(thd, 0, 0);
e.update_hash(val, val_len, type, charset, DERIVATION_NONE);
free_root(&thd->mem_root,0);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index eb879a1fd59..8f86d9990fe 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -64,14 +64,6 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
-#ifndef LL
-#ifdef HAVE_LONG_LONG
-#define LL(A) A ## LL
-#else
-#define LL(A) A ## L
-#endif
-#endif
-
extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
@@ -621,7 +613,7 @@ int mysqld_help (THD *thd, const char *text);
/* sql_prepare.cc */
void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
-void mysql_stmt_execute(THD *thd, char *packet);
+void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
void mysql_stmt_free(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
@@ -799,6 +791,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file;
extern char log_error_file[FN_REFLEN];
extern double log_10[32];
+extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables;
extern ulong created_tmp_tables, created_tmp_disk_tables, bytes_sent;
@@ -958,6 +951,8 @@ timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
void localtime_to_TIME(TIME *to, struct tm *from);
void calc_time_from_sec(TIME *to, long seconds, long microseconds);
+void make_truncated_value_warning(THD *thd, const char *str_val,
+ uint str_length, timestamp_type time_type);
extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
const char *format_str,
uint format_length);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5b6c592cd51..786390efd6b 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -305,6 +305,14 @@ ulong my_bind_addr; /* the address we bind to */
volatile ulong cached_thread_count= 0;
double log_10[32]; /* 10 potences */
+ulonglong log_10_int[20]=
+{
+ 1, 10, 100, 1000, 10000UL, 100000UL, 1000000UL, 10000000UL,
+ ULL(100000000), ULL(1000000000), ULL(10000000000), ULL(100000000000),
+ ULL(1000000000000), ULL(10000000000000), ULL(100000000000000),
+ ULL(1000000000000000), ULL(10000000000000000), ULL(100000000000000000),
+ ULL(1000000000000000000), ULL(10000000000000000000)
+};
time_t start_time;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 04fe2a8ea46..90c42035a91 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2500,7 +2500,7 @@ int set_var_user::check(THD *thd)
{
/*
Item_func_set_user_var can't substitute something else on its place =>
- 0 can be passed as last argument
+ 0 can be passed as last argument (reference on item)
*/
return (user_var_item->fix_fields(thd, 0, (Item**) 0) ||
user_var_item->check()) ? -1 : 0;
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 3a2d7a44c44..2d2a4472d9d 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -304,3 +304,4 @@ character-set=latin2
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 917ea3bf407..ca7c67552c3 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -298,3 +298,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 16cf2fd15de..2cb9e7e511b 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -306,3 +306,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 8c4e0530ed4..4e0da64408e 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -295,3 +295,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 8c7cc53ef06..8b912d10e97 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -300,3 +300,4 @@ character-set=latin7
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 78d729fc9f8..ef7385422fb 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -295,3 +295,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 142076a1f14..60454d0d011 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -307,3 +307,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index b9f47a54b35..4f695465bf5 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -295,3 +295,4 @@ character-set=greek
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 9deb3da88a2..fdd48f38ef1 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -297,3 +297,4 @@ character-set=latin2
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 9b5a081ec9d..b88117c0972 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -295,3 +295,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 1a17277cb90..c1b38e9ecbb 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -297,3 +297,4 @@ character-set=ujis
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 9b07afd16c9..932243eca38 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -295,3 +295,4 @@ character-set=euckr
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index aaba0f1afbe..05b55a582bd 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -297,3 +297,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index f205e07b3bb..c11e529efd5 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -297,3 +297,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 2c942d40f80..319deedc321 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -299,3 +299,4 @@ character-set=latin2
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index f3a8a484696..5151e612813 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -296,3 +296,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 72df2447f99..2c6ec81cc1d 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -299,3 +299,4 @@ character-set=latin2
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 3d37b2d60ce..00e931eb65a 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -297,3 +297,4 @@ character-set=koi8r
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index c68f9538dd2..dc15bbf4977 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -289,3 +289,4 @@ character-set=cp1250
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working"
"The MySQL server is running with the %s option so it cannot execute this statement"
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 35263024bb8..00b0dd9a0ae 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -303,3 +303,4 @@ character-set=latin2
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 3e0f67b453a..cb5d5b6df28 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -297,3 +297,4 @@ character-set=latin1
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index dc6759f91e0..5c60519e217 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -295,3 +295,4 @@ character-set=latin1
"MySQL är started i --skip-grant-tables mod. Pga av detta kan du inte använda detta program",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index fbf31744dca..7dd694e75ac 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -300,3 +300,4 @@ character-set=koi8u
"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
"The MySQL server is running with the %s option so it cannot execute this statement",
"Column '%-.100s' has duplicated value '%-.64s' in %s"
+"Truncated wrong %-.32s value: '%-.128s'"
diff --git a/sql/spatial.cc b/sql/spatial.cc
index f98799e26d1..ab415d9af10 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -19,13 +19,13 @@
/***************************** Gis_class_info *******************************/
-Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end]=
+Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static Geometry::Class_info **ci_collection_end=
- Geometry::ci_collection+Geometry::wkb_end;
+ Geometry::ci_collection+Geometry::wkb_end + 1;
Geometry::Class_info::Class_info(const char *name, int type_id,
void(*create_func)(void *)):
diff --git a/sql/spatial.h b/sql/spatial.h
index 26396dd0f90..cf07b364bb3 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -211,8 +211,7 @@ public:
virtual int geometry_n(uint32 num, String *result) const { return -1; }
public:
- static Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer,
- int type_id)
+ static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id)
{
Class_info *ci;
if (!(ci= find_class((int) type_id)))
@@ -251,7 +250,7 @@ public:
}
bool envelope(String *result) const;
- static Geometry::Class_info *ci_collection[Geometry::wkb_end];
+ static Class_info *ci_collection[wkb_end+1];
protected:
static Class_info *find_class(int type_id)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 37767c555e8..bdbb14f0819 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2141,9 +2141,8 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
while ((item= it++))
{
if (item->fix_fields(thd, tables, it.ref()) ||
- item->check_cols(1))
+ (item= *(it.ref()))->check_cols(1))
DBUG_RETURN(-1); /* purecov: inspected */
- item= *(it.ref()); //Item can be changed in fix fields
if (ref)
*(ref++)= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 95374b691c8..945414f532b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1169,8 +1169,12 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
ls= gl++;
Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
+ /*
+ Item_func_set_user_var can't substitute something else on its place =>
+ 0 can be passed as last argument (reference on item)
+ */
xx->fix_fields(thd,(TABLE_LIST*) thd->lex->select_lex.table_list.first,
- &item);
+ 0);
xx->fix_length_and_dec();
vars.push_back(xx);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5432a08a86f..97be60f3d19 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -658,7 +658,7 @@ public:
points to a lock object if the lock is present. See item_func.cc and
chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
- ULL *ull;
+ User_level_lock *ull;
#ifndef DBUG_OFF
uint dbug_sentry; // watch out for memory corruption
#endif
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index d0f241b3291..881f75566cd 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -207,11 +207,13 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
MYF(0),keyinfo->key_parts);
goto err;
}
- List_iterator_fast<Item> it_ke(*key_expr);
+ List_iterator<Item> it_ke(*key_expr);
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
- if (item->fix_fields(thd, tables, &item))
+ // 'item' can be changed by fix_fields() call
+ if (item->fix_fields(thd, tables, it_ke.ref()) ||
+ (item= *it_ke.ref())->check_cols(1))
goto err;
if (item->used_tables() & ~RAND_TABLE_BIT)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 97bae472757..3100737aaa5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1405,7 +1405,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_EXECUTE:
{
- mysql_stmt_execute(thd, packet);
+ mysql_stmt_execute(thd, packet, packet_length);
break;
}
case COM_LONG_DATA:
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index ac5b7847647..ab136668cfb 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -94,7 +94,8 @@ public:
bool long_data_used;
bool log_full_query;
#ifndef EMBEDDED_LIBRARY
- bool (*set_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
+ bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
+ uchar *read_pos);
#else
bool (*set_params_data)(Prepared_statement *st);
#endif
@@ -117,14 +118,6 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
enum { STMT_QUERY_LOG_LENGTH= 8192 };
-#ifdef EMBEDDED_LIBRARY
-#define SET_PARAM_FUNCTION(fn_name) \
-static void fn_name(Item_param *param, uchar **pos, ulong data_len)
-#else
-#define SET_PARAM_FUNCTION(fn_name) \
-static void fn_name(Item_param *param, uchar **pos)
-#endif
-
enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
/*
@@ -186,29 +179,38 @@ static bool send_prep_stmt(Prepared_statement *stmt,
*/
#ifndef EMBEDDED_LIBRARY
-static ulong get_param_length(uchar **packet)
+static ulong get_param_length(uchar **packet, ulong len)
{
reg1 uchar *pos= *packet;
+ if (len < 1)
+ return 0;
if (*pos < 251)
{
(*packet)++;
return (ulong) *pos;
}
+ if (len < 3)
+ return 0;
if (*pos == 252)
{
(*packet)+=3;
return (ulong) uint2korr(pos+1);
}
+ if (len < 4)
+ return 0;
if (*pos == 253)
{
(*packet)+=4;
return (ulong) uint3korr(pos+1);
}
+ if (len < 5)
+ return 0;
(*packet)+=9; // Must be 254 when here
+ /* TODO: why uint4korr here? (should be uint8korr) */
return (ulong) uint4korr(pos+1);
}
#else
-#define get_param_length(A) data_len
+#define get_param_length(packet, len) len
#endif /*!EMBEDDED_LIBRARY*/
/*
@@ -230,55 +232,80 @@ static ulong get_param_length(uchar **packet)
none
*/
-SET_PARAM_FUNCTION(set_param_tiny)
+void set_param_tiny(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 1)
+ return;
+#endif
param->set_int((longlong)(**pos));
*pos+= 1;
}
-SET_PARAM_FUNCTION(set_param_short)
+void set_param_short(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 2)
+ return;
+#endif
param->set_int((longlong)sint2korr(*pos));
*pos+= 2;
}
-SET_PARAM_FUNCTION(set_param_int32)
+void set_param_int32(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 4)
+ return;
+#endif
param->set_int((longlong)sint4korr(*pos));
*pos+= 4;
}
-SET_PARAM_FUNCTION(set_param_int64)
+void set_param_int64(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 8)
+ return;
+#endif
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
}
-SET_PARAM_FUNCTION(set_param_float)
+void set_param_float(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 4)
+ return;
+#endif
float data;
float4get(data,*pos);
param->set_double((double) data);
*pos+= 4;
}
-SET_PARAM_FUNCTION(set_param_double)
+void set_param_double(Item_param *param, uchar **pos, ulong len)
{
+#ifndef EMBEDDED_LIBRARY
+ if (len < 8)
+ return;
+#endif
double data;
float8get(data,*pos);
param->set_double((double) data);
*pos+= 8;
}
-SET_PARAM_FUNCTION(set_param_time)
+void set_param_time(Item_param *param, uchar **pos, ulong len)
{
ulong length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 8)
{
uchar *to= *pos;
TIME tm;
+ /* TODO: why length is compared with 8 here? */
tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
tm.day= (ulong) sint4korr(to+1);
@@ -294,11 +321,11 @@ SET_PARAM_FUNCTION(set_param_time)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_datetime)
+void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
uint length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 4)
{
uchar *to= *pos;
TIME tm;
@@ -324,11 +351,11 @@ SET_PARAM_FUNCTION(set_param_datetime)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_date)
+void set_param_date(Item_param *param, uchar **pos, ulong len)
{
ulong length;
- if ((length= get_param_length(pos)))
+ if ((length= get_param_length(pos, len)) >= 4)
{
uchar *to= *pos;
TIME tm;
@@ -346,11 +373,11 @@ SET_PARAM_FUNCTION(set_param_date)
*pos+= length;
}
-SET_PARAM_FUNCTION(set_param_str)
+void set_param_str(Item_param *param, uchar **pos, ulong len)
{
- ulong len= get_param_length(pos);
- param->set_value((const char *)*pos, len);
- *pos+= len;
+ ulong length= get_param_length(pos, len);
+ param->set_value((const char *)*pos, length);
+ *pos+= length;
}
static void setup_one_conversion_function(Item_param *param, uchar param_type)
@@ -405,8 +432,8 @@ static void setup_one_conversion_function(Item_param *param, uchar param_type)
and if binary/update log is set, generate the valid query.
*/
-static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
- uchar *read_pos)
+static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end)
{
THD *thd= stmt->thd;
Item_param **begin= stmt->param_array;
@@ -428,7 +455,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
res= param->query_val_str(&str);
else
{
- if (is_param_null(pos, it - begin))
+ if (is_param_null(null_array, it - begin))
{
param->maybe_null= param->null_value= 1;
res= &my_null_string;
@@ -436,7 +463,9 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
else
{
param->maybe_null= param->null_value= 0;
- param->set_param_func(param, &read_pos);
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
+ param->set_param_func(param, &read_pos, data_end - read_pos);
res= param->query_val_str(&str);
}
}
@@ -452,8 +481,8 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
}
-static bool insert_params(Prepared_statement *stmt, uchar *pos,
- uchar *read_pos)
+static bool insert_params(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end)
{
Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count;
@@ -465,20 +494,23 @@ static bool insert_params(Prepared_statement *stmt, uchar *pos,
Item_param *param= *it;
if (!param->long_data_supplied)
{
- if (is_param_null(pos, it - begin))
+ if (is_param_null(null_array, it - begin))
param->maybe_null= param->null_value= 1;
else
{
param->maybe_null= param->null_value= 0;
- param->set_param_func(param, &read_pos);
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
+ param->set_param_func(param, &read_pos, data_end - read_pos);
}
}
}
DBUG_RETURN(0);
}
+
static bool setup_conversion_functions(Prepared_statement *stmt,
- uchar **data)
+ uchar **data, uchar *data_end)
{
/* skip null bits */
uchar *read_pos= *data + (stmt->param_count+7) / 8;
@@ -495,6 +527,8 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
Item_param **end= it + stmt->param_count;
for (; it < end; ++it)
{
+ if (read_pos >= data_end)
+ DBUG_RETURN(1);
setup_one_conversion_function(*it, *read_pos);
read_pos+= 2;
}
@@ -1072,7 +1106,7 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
*/
-void mysql_stmt_execute(THD *thd, char *packet)
+void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
@@ -1097,10 +1131,11 @@ void mysql_stmt_execute(THD *thd, char *packet)
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
+ uchar *packet_end= (uchar *) packet + packet_length - 1;
packet+= 4;
uchar *null_array= (uchar *) packet;
- if (setup_conversion_functions(stmt, (uchar **) &packet) ||
- stmt->set_params(stmt, null_array, (uchar *) packet))
+ if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
+ stmt->set_params(stmt, null_array, (uchar *) packet, packet_end))
goto set_params_data_err;
}
#else
@@ -1159,6 +1194,7 @@ set_params_data_err:
void mysql_stmt_reset(THD *thd, char *packet)
{
+ /* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
@@ -1189,6 +1225,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
void mysql_stmt_free(THD *thd, char *packet)
{
+ /* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 8a5a9564d3e..32c5f0bfdab 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -662,8 +662,6 @@ err:
int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
{
int slave_errno= 0;
- if (!thd)
- thd = current_thd;
int thread_mask;
DBUG_ENTER("start_slave");
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7605016dbe1..467c1295517 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -842,8 +842,7 @@ JOIN::optimize()
for (uint i_h = const_tables; i_h < tables; i_h++)
{
TABLE* table_h = join_tab[i_h].table;
- if (table_h->db_type == DB_TYPE_INNODB)
- table_h->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
+ table_h->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
}
}
#endif
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9d1855ef936..f49a73dbf2d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -365,9 +365,6 @@ void check_duplicates_in_interval(const char *set_or_name,
unsigned int old_count= typelib->count;
const char **old_type_names= typelib->type_names;
- if (typelib->count <= 1)
- return;
-
old_count= typelib->count;
old_type_names= typelib->type_names;
const char **cur_value= typelib->type_names;
@@ -377,7 +374,7 @@ void check_duplicates_in_interval(const char *set_or_name,
typelib->count--;
if (find_type((char*)*cur_value,typelib,1))
{
- push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_DUPLICATED_VALUE_IN_TYPE,
ER(ER_DUPLICATED_VALUE_IN_TYPE),
name,*cur_value,set_or_name);
@@ -2979,12 +2976,10 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
/* calculating table's checksum */
ha_checksum crc= 0;
- if (t->db_type == DB_TYPE_INNODB) {
- /* InnoDB must be told explicitly to retrieve all columns, because
- this function does not set field->query_id in the columns to the
- current query id */
- t->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- }
+ /* InnoDB must be told explicitly to retrieve all columns, because
+ this function does not set field->query_id in the columns to the
+ current query id */
+ t->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (t->file->rnd_init(1))
protocol->store_null();
diff --git a/sql/time.cc b/sql/time.cc
index 1dff0c62edf..376ad6926b8 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -391,9 +391,11 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
ulong not_zero_date, allow_space;
bool is_internal_format;
const char *pos, *last_field_pos;
+ const char *str_begin= str;
const char *end=str+length;
const uchar *format_position;
bool found_delimitier= 0, found_space= 0;
+ uint frac_pos, frac_len;
DBUG_ENTER("str_to_TIME");
DBUG_PRINT("ENTER",("str: %.*s",length,str));
@@ -482,7 +484,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
str++;
}
- date_len[i]+= (uint) (str - start);
+ date_len[i]= (uint) (str - start);
if (tmp_value > 999999) // Impossible date part
DBUG_RETURN(TIMESTAMP_NONE);
date[i]=tmp_value;
@@ -535,9 +537,9 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
{
if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
{
- if (str[1] == 'p' || str[1] == 'P')
+ if (str[0] == 'p' || str[0] == 'P')
add_hours= 12;
- else if (str[1] != 'a' || str[1] != 'A')
+ else if (str[0] != 'a' || str[0] != 'A')
continue; // Not AM/PM
str+= 2; // Skip AM/PM
/* Skip space after AM/PM */
@@ -569,7 +571,13 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
l_time->hour= date[(uint) format_position[3]];
l_time->minute= date[(uint) format_position[4]];
l_time->second= date[(uint) format_position[5]];
- l_time->second_part= date[(uint) format_position[6]];
+
+ frac_pos= (uint) format_position[6];
+ frac_len= date_len[frac_pos];
+ if (frac_len < 6)
+ date[frac_pos]*= (uint) log_10_int[6 - frac_len];
+ l_time->second_part= date[frac_pos];
+
if (format_position[7] != (uchar) 255)
{
if (l_time->hour > 12)
@@ -585,6 +593,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
l_time->hour= date[3];
l_time->minute= date[4];
l_time->second= date[5];
+ if (date_len[6] < 6)
+ date[6]*= (uint) log_10_int[6 - date_len[6]];
l_time->second_part=date[6];
}
l_time->neg= 0;
@@ -614,15 +624,17 @@ str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
current_thd->cuted_fields++;
goto err;
}
- if (str != end && current_thd->count_cuted_fields)
+
+ l_time->time_type= (number_of_fields <= 3 ?
+ TIMESTAMP_DATE : TIMESTAMP_DATETIME);
+
+ for (; str != end ; str++)
{
- for (; str != end ; str++)
+ if (!my_isspace(&my_charset_latin1,*str))
{
- if (!my_isspace(&my_charset_latin1,*str))
- {
- current_thd->cuted_fields++;
- break;
- }
+ make_truncated_value_warning(current_thd, str_begin, length,
+ l_time->time_type);
+ break;
}
}
@@ -686,6 +698,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
{
long date[5],value;
const char *end=str+length, *end_of_days;
+ const char *str_begin= str;
bool found_days,found_hours;
uint state;
@@ -706,7 +719,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
{ // Probably full timestamp
enum timestamp_type res= str_to_TIME(str,length,l_time,
(TIME_FUZZY_DATE |
- TIME_DATETIME_ONLY));
+ TIME_DATETIME_ONLY));
if ((int) res >= (int) TIMESTAMP_DATETIME_ERROR)
return res == TIMESTAMP_DATETIME_ERROR;
}
@@ -784,6 +797,8 @@ fractional:
my_isdigit(&my_charset_latin1,str[0]) &&
field_length--)
value=value*10 + (uint) (uchar) (*str - '0');
+ if (field_length)
+ value*= (long) log_10_int[field_length];
date[4]=value;
}
else
@@ -796,12 +811,12 @@ fractional:
str++;
if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
{
- if (str[1] == 'p' || str[1] == 'P')
+ if (str[0] == 'p' || str[0] == 'P')
{
str+= 2;
date[1]= date[1]%12 + 12;
}
- else if (str[1] == 'a' || str[1] == 'A')
+ else if (str[0] == 'a' || str[0] == 'A')
str+=2;
}
}
@@ -822,13 +837,14 @@ fractional:
l_time->time_type= TIMESTAMP_TIME;
/* Check if there is garbage at end of the TIME specification */
- if (str != end && current_thd->count_cuted_fields)
+ if (str != end)
{
do
{
if (!my_isspace(&my_charset_latin1,*str))
{
- current_thd->cuted_fields++;
+ make_truncated_value_warning(current_thd, str_begin, length,
+ TIMESTAMP_TIME);
break;
}
} while (++str != end);
@@ -1265,3 +1281,35 @@ void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str)
str->length(length);
str->set_charset(&my_charset_bin);
}
+
+void make_truncated_value_warning(THD *thd, const char *str_val,
+ uint str_length, timestamp_type time_type)
+{
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ const char *type_str;
+
+ char buff[128];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ str.append(str_val, str_length);
+ str.append('\0');
+
+ switch (time_type) {
+ case TIMESTAMP_DATE:
+ type_str= "date";
+ break;
+ case TIMESTAMP_DATETIME:
+ type_str= "datetime";
+ break;
+ case TIMESTAMP_TIME:
+ type_str= "time";
+ break;
+ default:
+ type_str= "string";
+ break;
+ }
+ sprintf(warn_buff, ER(ER_TRUNCATED_WRONG_VALUE),
+ type_str, str.ptr());
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TRUNCATED_WRONG_VALUE, warn_buff);
+}
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 719ae14f653..6e7d0b849e2 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -262,9 +262,9 @@ long my_strntol_8bit(CHARSET_INFO *cs,
{
if (c>='0' && c<='9')
c -= '0';
- else if (c>='A' && c<='F')
+ else if (c>='A' && c<='Z')
c = c - 'A' + 10;
- else if (c>='a' && c<='f')
+ else if (c>='a' && c<='z')
c = c - 'a' + 10;
else
break;
@@ -384,9 +384,9 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs,
{
if (c>='0' && c<='9')
c -= '0';
- else if (c>='A' && c<='F')
+ else if (c>='A' && c<='Z')
c = c - 'A' + 10;
- else if (c>='a' && c<='f')
+ else if (c>='a' && c<='z')
c = c - 'a' + 10;
else
break;
@@ -499,9 +499,9 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
{
if (c>='0' && c<='9')
c -= '0';
- else if (c>='A' && c<='F')
+ else if (c>='A' && c<='Z')
c = c - 'A' + 10;
- else if (c>='a' && c<='f')
+ else if (c>='a' && c<='z')
c = c - 'a' + 10;
else
break;
@@ -622,9 +622,9 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
{
if (c>='0' && c<='9')
c -= '0';
- else if (c>='A' && c<='F')
+ else if (c>='A' && c<='Z')
c = c - 'A' + 10;
- else if (c>='a' && c<='f')
+ else if (c>='a' && c<='z')
c = c - 'a' + 10;
else
break;
diff --git a/strings/strtod.c b/strings/strtod.c
index 243322cb945..aa0f7aa4336 100644
--- a/strings/strtod.c
+++ b/strings/strtod.c
@@ -26,9 +26,13 @@
*/
-#include "my_base.h"
+#include "my_base.h" /* Includes errno.h */
#include "m_ctype.h"
+#ifndef EOVERFLOW
+#define EOVERFLOW 84
+#endif
+
static double scaler10[] = {
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
};
@@ -36,6 +40,7 @@ static double scaler1[] = {
1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
};
+
double my_strtod(const char *str, char **end)
{
double result= 0.0;
@@ -92,10 +97,10 @@ double my_strtod(const char *str, char **end)
}
if (exp >= 1000)
{
- if (neg)
- result= 0.0;
- else
- overflow=1;
+ if (neg)
+ result= 0.0;
+ else
+ overflow= 1;
goto done;
}
while (exp >= 100)
@@ -115,10 +120,10 @@ done:
if (end)
*end = (char *)str;
- if (overflow || ((overflow=isinf(result))))
+ if (overflow || isinf(result))
{
- result=DBL_MAX;
- errno=EOVERFLOW;
+ result= DBL_MAX;
+ errno= EOVERFLOW;
}
return negative ? -result : result;