Merge mysql.com:/home/pz/mysql/mysql-4.1-root

into mysql.com:/home/pz/mysql/mysql-4.1
This commit is contained in:
peter@mysql.com 2002-11-24 17:35:24 +03:00
commit d2aa1fb8e7
47 changed files with 1258 additions and 987 deletions

View file

@ -57,6 +57,9 @@ typedef int my_socket;
#include "mysql_com.h"
#include "mysql_version.h"
#include "typelib.h"
#ifndef DBUG_OFF
#define CHECK_EXTRA_ARGUMENTS
#endif
extern unsigned int mysql_port;
extern char *mysql_unix_port;
@ -424,7 +427,7 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con,
*/
/* statement state */
enum MY_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE };
enum PREP_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE };
/* bind structure */
typedef struct st_mysql_bind
@ -442,7 +445,7 @@ typedef struct st_mysql_bind
my_bool long_ended; /* All data supplied for long */
unsigned int param_number; /* For null count and error messages */
void (*store_param_func)(NET *net, struct st_mysql_bind *param);
char *(*fetch_result)(struct st_mysql_bind *, const char *row);
void (*fetch_result)(struct st_mysql_bind *, unsigned char **row);
} MYSQL_BIND;
@ -462,10 +465,12 @@ typedef struct st_mysql_stmt
unsigned long long_length; /* long buffer alloced length */
unsigned long stmt_id; /* Id for prepared statement */
unsigned int last_errno; /* error code */
enum MY_STMT_STATE state; /* statement state */
enum PREP_STMT_STATE state; /* statement state */
char last_error[MYSQL_ERRMSG_SIZE]; /* error message */
my_bool long_alloced; /* flag to indicate long alloced */
my_bool types_supplied; /* to indicate types supply */
my_bool send_types_to_server; /* to indicate types supply to server */
my_bool param_buffers; /* to indicate the param bound buffers */
my_bool res_buffers; /* to indicate the result bound buffers */
} MYSQL_STMT;

View file

@ -312,6 +312,7 @@ void my_thread_end(void);
#endif
#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */
#define MYSQL_STMT_HEADER 4
#define MYSQL_LONG_DATA_HEADER 8
#endif

View file

@ -261,4 +261,5 @@
#define ER_CORRUPT_HELP_DB 1242
#define ER_CYCLIC_REFERENCE 1243
#define ER_AUTO_CONVERT 1244
#define ER_ERROR_MESSAGES 245
#define ER_ILLEGAL_REFERENCE 1245
#define ER_ERROR_MESSAGES 246

View file

@ -59,7 +59,7 @@ const char *client_errors[]=
"No parameters exists in the statement",
"Invalid parameter number",
"Can't send long data for non string or binary data types (parameter: %d)",
"Using not supported parameter type: %d (parameter: %d)"
"Using un supported parameter type: %d (parameter: %d)"
"Shared memory (%lu)",
"Can't open shared memory. Request event don't create (%lu)",
"Can't open shared memory. Answer event don't create (%lu)",
@ -113,7 +113,7 @@ const char *client_errors[]=
"No parameters exists in the statement",
"Invalid parameter number",
"Can't send long data for non string or binary data types (parameter: %d)",
"Using not supported parameter type: %d (parameter: %d)"
"Using un supported parameter type: %d (parameter: %d)"
"Shared memory (%lu)",
"Can't open shared memory. Request event don't create (%lu)",
"Can't open shared memory. Answer event don't create (%lu)",
@ -165,7 +165,7 @@ const char *client_errors[]=
"No parameters exists in the statement",
"Invalid parameter number",
"Can't send long data for non string or binary data types (parameter: %d)",
"Using not supported parameter type: %d (parameter: %d)"
"Using un supported parameter type: %d (parameter: %d)"
"Shared memory (%lu)",
"Can't open shared memory. Request event don't create (%lu)",
"Can't open shared memory. Answer event don't create (%lu)",

View file

@ -928,7 +928,7 @@ static const char *default_options[]=
"connect-timeout", "local-infile", "disable-local-infile",
"replication-probe", "enable-reads-from-master", "repl-parse-query",
"ssl-cipher","protocol", "shared_memory_base_name",
NullS
NullS
};
static TYPELIB option_types={array_elements(default_options)-1,
@ -1740,7 +1740,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
#ifdef HAVE_OPENSSL
#ifdef HAVE_OPENSLL
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
@ -1754,7 +1754,7 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->options.ssl_cipher= 0;
mysql->options.use_ssl = FALSE;
mysql->connector_fd = 0;
#endif /* HAVE_OPENSSL */
#endif /* HAVE_OPENSLL */
}
/**************************************************************************
@ -2645,7 +2645,7 @@ get_info:
{
mysql->affected_rows= net_field_length_ll(&pos);
mysql->insert_id= net_field_length_ll(&pos);
if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
if (protocol_41(mysql))
{
mysql->server_status=uint2korr(pos); pos+=2;
mysql->warning_count=uint2korr(pos); pos+=2;
@ -3728,10 +3728,10 @@ MYSQL_STMT *STDCALL
mysql_prepare(MYSQL *mysql, const char *query, ulong length)
{
MYSQL_STMT *stmt;
DBUG_ENTER("mysql_real_prepare");
DBUG_ENTER("mysql_prepare");
DBUG_ASSERT(mysql != 0);
#ifdef EXTRA_CHECK_ARGUMENTS
#ifdef CHECK_EXTRA_ARGUMENTS
if (!query)
{
set_mysql_error(mysql, CR_NULL_POINTER);
@ -3752,7 +3752,6 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
mysql_stmt_close(stmt);
DBUG_RETURN(0);
}
stmt->state= MY_ST_PREPARE;
init_alloc_root(&stmt->mem_root,8192,0);
if (read_prepare_result(mysql, stmt))
@ -3760,8 +3759,8 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
mysql_stmt_close(stmt);
DBUG_RETURN(0);
}
stmt->mysql= mysql;
stmt->state= MY_ST_PREPARE;
stmt->mysql= mysql;
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
DBUG_RETURN(stmt);
}
@ -3897,7 +3896,7 @@ static void store_param_str(NET *net, MYSQL_BIND *param)
ulong length= *param->length;
char *to= (char *) net_store_length((char *) net->write_pos, length);
memcpy(to, param->buffer, length);
net->write_pos+= length;
net->write_pos= to+length;
}
@ -3931,17 +3930,19 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
MYSQL *mysql= stmt->mysql;
NET *net = &mysql->net;
DBUG_ENTER("store_param");
DBUG_PRINT("enter",("type : %d, buffer :%lx", param->buffer_type,
param->buffer));
/* Allocate for worst case (long string) */
if ((my_realloc_str(net, 9 + *param->length)))
return 1;
if (!param->buffer)
DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %d", param->buffer_type,
param->buffer ? param->buffer : "0", *param->length));
if (param->is_null || param->buffer_type == MYSQL_TYPE_NULL)
store_param_null(net, param);
else
{
/* Allocate for worst case (long string) */
if ((my_realloc_str(net, 9 + *param->length)))
DBUG_RETURN(1);
(*param->store_param_func)(net, param);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
@ -3953,13 +3954,13 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length)
{
MYSQL *mysql= stmt->mysql;
NET *net= &mysql->net;
char buff[4];
char buff[MYSQL_STMT_HEADER];
DBUG_ENTER("execute");
DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length));
mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
if (advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff), packet,
if (advanced_command(mysql, COM_EXECUTE, buff, MYSQL_STMT_HEADER, packet,
length, 1) ||
mysql_read_query_result(mysql))
{
@ -3967,12 +3968,14 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length)
DBUG_RETURN(1);
}
stmt->state= MY_ST_EXECUTE;
if (stmt->bind)
mysql_free_result(stmt->result);
#if USED_IN_FETCH
if (stmt->res_buffers) /* Result buffers exists, cache results */
{
mysql_free_result(stmt->result);
stmt->result= mysql_store_result(mysql);
}
#endif
DBUG_RETURN(0);
}
@ -3983,8 +3986,6 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length)
int STDCALL mysql_execute(MYSQL_STMT *stmt)
{
ulong length;
uint null_count;
DBUG_ENTER("mysql_execute");
if (stmt->state == MY_ST_UNKNOWN)
@ -3998,14 +3999,18 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
NET *net= &stmt->mysql->net;
MYSQL_BIND *param, *param_end;
char *param_data;
my_bool result;
ulong length;
uint null_count;
my_bool result;
if (!stmt->params)
#ifdef CHECK_EXTRA_ARGUMENTS
if (!stmt->param_buffers)
{
/* Parameters exists, but no bound buffers */
set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND);
DBUG_RETURN(1);
}
#endif
net_clear(net); /* Sets net->write_pos */
/* Reserve place for null-marker bytes */
null_count= (stmt->param_count+7) /8;
@ -4014,10 +4019,9 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
param_end= stmt->params + stmt->param_count;
/* In case if buffers (type) altered, indicate to server */
*(net->write_pos)++= (uchar) stmt->types_supplied;
if (!stmt->types_supplied)
*(net->write_pos)++= (uchar) stmt->send_types_to_server;
if (stmt->send_types_to_server)
{
stmt->types_supplied=1;
/*
Store types of parameters in first in first package
that is sent to the server.
@ -4031,21 +4035,22 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
/* Check for long data which has not been propery given/terminated */
if (param->is_long_data)
{
if (!param->long_ended)
DBUG_RETURN(MYSQL_NEED_DATA);
if (!param->long_ended)
DBUG_RETURN(MYSQL_NEED_DATA);
}
else if (store_param(stmt, param))
DBUG_RETURN(1);
DBUG_RETURN(1);
}
length= (ulong) (net->write_pos - net->buff);
/* TODO: Look into avoding the following memdup */
if (!(param_data= my_memdup((byte *) net->buff, length, MYF(0))))
if (!(param_data= my_memdup( net->buff, length, MYF(0))))
{
set_stmt_error(stmt, CR_OUT_OF_MEMORY);
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));
DBUG_RETURN(result);
}
@ -4108,15 +4113,19 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param->param_number);
DBUG_RETURN(1);
}
/*
If param->length is not given, change it to point to bind_length.
This way we can always use *param->length to get the length of data
*/
if (!param->length)
param->length= &param->bind_length;
/* Setup data copy functions for the different supported types */
switch (param->buffer_type) {
case MYSQL_TYPE_NULL:
param->is_null=1;
break;
case MYSQL_TYPE_TINY:
param->bind_length= 1;
param->store_param_func= store_param_tinyint;
@ -4138,12 +4147,13 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param->store_param_func= store_param_float;
break;
case MYSQL_TYPE_DOUBLE:
param->bind_length= 4;
param->bind_length= 8;
param->store_param_func= store_param_double;
break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
param->bind_length= param->buffer_length;
@ -4156,7 +4166,8 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
}
}
/* We have to send/resendtype information to MySQL */
stmt->types_supplied= 0;
stmt->send_types_to_server= 1;
stmt->param_buffers= 1;
DBUG_RETURN(0);
}
@ -4230,6 +4241,73 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number,
Fetch-bind related implementations
*********************************************************************/
/****************************************************************************
Functions to fetch data to application buffers
All functions has the following characteristics:
SYNOPSIS
fetch_result_xxx()
param MySQL bind param
row Row value
RETURN VALUES
0 ok
1 Error (Can't alloc net->buffer)
****************************************************************************/
static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row)
{
*param->buffer= (uchar) **row;
*row++;
}
static void fetch_result_short(MYSQL_BIND *param, uchar **row)
{
short value= *(short *)row;
int2store(param->buffer, value);
*row+=2;
}
static void fetch_result_int32(MYSQL_BIND *param, uchar **row)
{
int32 value= *(int32 *)row;
int4store(param->buffer, value);
*row+=4;
}
static void fetch_result_int64(MYSQL_BIND *param, uchar **row)
{
longlong value= *(longlong *)row;
int8store(param->buffer, value);
*row+=8;
}
static void fetch_result_float(MYSQL_BIND *param, uchar **row)
{
float value;
float4get(value,*row);
float4store(param->buffer, *row);
*row+=4;
}
static void fetch_result_double(MYSQL_BIND *param, uchar **row)
{
double value;
float8get(value,*row);
float8store(param->buffer, value);
*row+=8;
}
static void fetch_result_str(MYSQL_BIND *param, uchar **row)
{
ulong length= net_field_length(row);
memcpy(param->buffer, (char *)*row, length);
*param->length= length;
*row+=length;
}
/*
Setup the bind buffers for resultset processing
*/
@ -4241,21 +4319,62 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_ENTER("mysql_bind_result");
DBUG_ASSERT(stmt != 0);
#ifdef EXTRA_CHECK_ARGUMENTS
#ifdef CHECK_EXTRA_ARGUMENTS
if (!bind)
{
set_stmt_error(stmt, CR_NULL_POINTER);
DBUG_RETURN(1);
}
#endif
bind_count= stmt->result->field_count;
bind_count= stmt->field_count;
memcpy((char*) stmt->bind, (char*) bind,
sizeof(MYSQL_BIND)*bind_count);
for (param= stmt->bind, end= param+bind_count; param < end ; param++)
{
/* TODO: Set up convert functions like in mysql_bind_param */
/* Setup data copy functions for the different supported types */
switch (param->buffer_type) {
case MYSQL_TYPE_TINY:
param->bind_length= 1;
param->fetch_result= fetch_result_tinyint;
break;
case MYSQL_TYPE_SHORT:
param->bind_length= 2;
param->fetch_result= fetch_result_short;
break;
case MYSQL_TYPE_LONG:
param->bind_length= 4;
param->fetch_result= fetch_result_int32;
break;
case MYSQL_TYPE_LONGLONG:
param->bind_length= 8;
param->fetch_result= fetch_result_int64;
break;
case MYSQL_TYPE_FLOAT:
param->bind_length= 4;
param->fetch_result= fetch_result_float;
break;
case MYSQL_TYPE_DOUBLE:
param->bind_length= 8;
param->fetch_result= fetch_result_double;
break;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
param->length= &param->buffer_length;
param->fetch_result= fetch_result_str;
break;
default:
sprintf(stmt->last_error, ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
param->buffer_type, param->param_number);
DBUG_RETURN(1);
}
if (!param->length)
param->length= &param->bind_length;
}
stmt->res_buffers= 1;
DBUG_RETURN(0);
}
@ -4265,16 +4384,16 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
*/
static my_bool
my_fetch_row(MYSQL_STMT *stmt, MYSQL_RES *result, const byte *row)
stmt_fetch_row(MYSQL_STMT *stmt, uchar **row)
{
MYSQL_BIND *bind, *end;
uchar *null_ptr= (uchar*) row, bit;
result->row_count++;
row+= (result->field_count+7)/8;
/* Copy complete row to application buffers */
uchar *null_ptr= (uchar*) *row, bit;
*row+= (stmt->field_count+7)/8;
bit=1;
for (bind= stmt->bind, end= (MYSQL_BIND *) bind + result->field_count;
/* Copy complete row to application buffers */
for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count;
bind < end;
bind++)
{
@ -4283,7 +4402,7 @@ my_fetch_row(MYSQL_STMT *stmt, MYSQL_RES *result, const byte *row)
else
{
bind->is_null= 0;
row= (byte*) (*bind->fetch_result)(bind, (char*) row);
(*bind->fetch_result)(bind, row);
}
if (! (bit<<=1) & 255)
{
@ -4294,12 +4413,9 @@ my_fetch_row(MYSQL_STMT *stmt, MYSQL_RES *result, const byte *row)
return 0;
}
static int
read_binary_data(MYSQL *mysql)
{
ulong pkt_len;
if ((pkt_len= net_safe_read(mysql)) == packet_error)
static int read_binary_data(MYSQL *mysql)
{
if (packet_error == net_safe_read(mysql))
return -1;
if (mysql->net.read_pos[0])
return 1; /* End of data */
@ -4313,57 +4429,30 @@ read_binary_data(MYSQL *mysql)
int STDCALL mysql_fetch(MYSQL_STMT *stmt)
{
MYSQL_RES *result;
MYSQL *mysql= stmt->mysql;
DBUG_ENTER("mysql_fetch");
result= stmt->result;
if (!result)
DBUG_RETURN(MYSQL_NO_DATA);
if (!result->data)
if (stmt->res_buffers)
{
MYSQL *mysql= stmt->mysql;
if (!result->eof)
int res;
if (!(res= read_binary_data(mysql)))
{
int res;
if (!(res= read_binary_data(result->handle)))
DBUG_RETURN((int) my_fetch_row(stmt, result,
(byte*) mysql->net.read_pos+1));
DBUG_PRINT("info", ("end of data"));
result->eof= 1;
result->handle->status= MYSQL_STATUS_READY;
/* Don't clear handle in mysql_free_results */
result->handle= 0;
if (res < 0) /* Network error */
{
set_stmt_errmsg(stmt,(char *)mysql->net.last_error,
mysql->net.last_errno);
DBUG_RETURN(MYSQL_STATUS_ERROR);
}
if (stmt->res_buffers)
DBUG_RETURN((int) stmt_fetch_row(stmt,(uchar **) &mysql->net.read_pos+1));
DBUG_RETURN(0);
}
DBUG_PRINT("info", ("end of data"));
mysql->status= MYSQL_STATUS_READY;
if (res < 0) /* Network error */
{
set_stmt_errmsg(stmt,(char *)mysql->net.last_error,
mysql->net.last_errno);
DBUG_RETURN(MYSQL_STATUS_ERROR);
}
DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
}
{
/*
For prepared statements, the row data is a string of binary bytes,
not a set of string pointers as for normal statements
It's however convenient to use the data pointer also for prepared
statements.
*/
MYSQL_ROW values;
if (!result->data_cursor)
{
DBUG_PRINT("info", ("end of data"));
result->current_row= (MYSQL_ROW) NULL;
DBUG_RETURN(MYSQL_NO_DATA);
}
values= result->data_cursor->data;
result->data_cursor= result->data_cursor->next;
DBUG_RETURN((int) my_fetch_row(stmt,result, (byte*) values));
}
DBUG_RETURN(0);
DBUG_RETURN(0); //?? do we need to set MYSQL_STATUS_READY ?
}
@ -4380,17 +4469,15 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
my_bool error=0;
DBUG_ENTER("mysql_stmt_close");
if (stmt->state)
if (stmt->state != MY_ST_UNKNOWN)
{
char buff[4];
int4store(buff, stmt->stmt_id);
error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 0);
}
mysql_free_result(stmt->result);
free_root(&stmt->mem_root, MYF(0));
my_free((gptr) stmt->query, MYF(MY_WME | MY_ALLOW_ZERO_PTR));
my_free((gptr) stmt->bind, MY_ALLOW_ZERO_PTR);
my_free((gptr) stmt->params, MY_ALLOW_ZERO_PTR);
my_free((gptr) stmt, MYF(MY_WME));
DBUG_RETURN(error);
}

View file

@ -102,8 +102,24 @@ EXPORTS
mysql_add_slave
mysql_warning_count
mysql_warnings
mysql_prepare
mysql_execute
mysql_param_count
mysql_bind_param
mysql_bind_result
mysql_prepare_result
mysql_stmt_close
mysql_stmt_error
mysql_stmt_errno
mysql_fetch
mysql_send_long_data
mysql_multi_query
mysql_next_result
mysql_commit
mysql_rollback
mysql_autocommit

View file

@ -9,9 +9,14 @@ SELECT (SELECT (SELECT 0 UNION SELECT 0));
(SELECT (SELECT 0 UNION SELECT 0))
0
SELECT (SELECT 1 FROM (SELECT 1) HAVING a=1) as a;
Cyclic reference on subqueries
Reference 'a' not supported (forward reference in item list)
SELECT (SELECT 1 FROM (SELECT 1) HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) HAVING a=1) as b;
Cyclic reference on subqueries
Reference 'b' not supported (forward reference in item list)
SELECT (SELECT 1),MAX(1) FROM (SELECT 1);
(SELECT 1) MAX(1)
1 1
SELECT (SELECT a) as a;
Reference 'a' not supported (forward reference in item list)
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
@ -20,6 +25,8 @@ create table t4 (a int, b int);
insert into t1 values (2);
insert into t2 values (1,7),(2,7);
insert into t4 values (4,8),(3,8),(5,9);
select (select a from t1 where t1.a = a1) as a2, (select b from t2 where t2.b=a2) as a1;
Reference 'a1' not supported (forward reference in item list)
select (select a from t1 where t1.a=t2.a), a from t2;
(select a from t1 where t1.a=t2.a) a
NULL 1
@ -278,6 +285,12 @@ PRIMARY KEY (`numeropost`,`numreponse`),
UNIQUE KEY `numreponse` (`numreponse`),
KEY `pseudo` (`pseudo`,`numeropost`)
) TYPE=MyISAM;
SELECT (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=a),numreponse FROM (SELECT * FROM threadhardwarefr7) as a;
Reference 'numreponse' not supported (forward reference in item list)
SELECT numreponse, (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=a) FROM (SELECT * FROM threadhardwarefr7) as a;
Unknown column 'a' in 'having clause'
SELECT numreponse, (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=1) FROM (SELECT * FROM threadhardwarefr7) as a;
numreponse (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=1)
INSERT INTO threadhardwarefr7 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test');
EXPLAIN SELECT numreponse FROM threadhardwarefr7 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM threadhardwarefr7 WHERE numeropost='1');
Subselect returns more than 1 record

View file

@ -1,10 +1,13 @@
select (select 2);
SELECT (SELECT 1) UNION SELECT (SELECT 2);
SELECT (SELECT (SELECT 0 UNION SELECT 0));
-- error 1243
-- error 1245
SELECT (SELECT 1 FROM (SELECT 1) HAVING a=1) as a;
-- error 1243
-- error 1245
SELECT (SELECT 1 FROM (SELECT 1) HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) HAVING a=1) as b;
SELECT (SELECT 1),MAX(1) FROM (SELECT 1);
-- error 1245
SELECT (SELECT a) as a;
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
@ -13,6 +16,8 @@ create table t4 (a int, b int);
insert into t1 values (2);
insert into t2 values (1,7),(2,7);
insert into t4 values (4,8),(3,8),(5,9);
-- error 1245
select (select a from t1 where t1.a = a1) as a2, (select b from t2 where t2.b=a2) as a1;
select (select a from t1 where t1.a=t2.a), a from t2;
select (select a from t1 where t1.a=t2.b), a from t2;
select (select a from t1), a from t2;
@ -176,6 +181,11 @@ CREATE TABLE `threadhardwarefr7` (
UNIQUE KEY `numreponse` (`numreponse`),
KEY `pseudo` (`pseudo`,`numeropost`)
) TYPE=MyISAM;
-- error 1245
SELECT (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=a),numreponse FROM (SELECT * FROM threadhardwarefr7) as a;
-- error 1054
SELECT numreponse, (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=a) FROM (SELECT * FROM threadhardwarefr7) as a;
SELECT numreponse, (SELECT numeropost FROM threadhardwarefr7 HAVING numreponse=1) FROM (SELECT * FROM threadhardwarefr7) as a;
INSERT INTO threadhardwarefr7 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test');
-- error 1240
EXPLAIN SELECT numreponse FROM threadhardwarefr7 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM threadhardwarefr7 WHERE numeropost='1');

View file

@ -34,7 +34,8 @@ void item_init(void)
item_user_lock_init();
}
Item::Item()
Item::Item():
fixed(0)
{
marker=0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
@ -139,6 +140,7 @@ CHARSET_INFO * Item::thd_charset() const
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{
set_field(f);
fixed= 1; // This item is not needed in fix_fields
}
@ -315,32 +317,27 @@ void Item_param::set_null()
void Item_param::set_int(longlong i)
{
int_value=(longlong)i;
item_result_type = INT_RESULT;
item_type = INT_ITEM;
}
void Item_param::set_double(double value)
{
real_value=value;
item_result_type = REAL_RESULT;
item_type = REAL_ITEM;
}
void Item_param::set_value(const char *str, uint length, CHARSET_INFO *cs)
void Item_param::set_value(const char *str, uint length)
{
str_value.set(str,length,cs);
item_result_type = STRING_RESULT;
str_value.set(str,length,thd_charset());
item_type = STRING_ITEM;
}
void Item_param::set_longdata(const char *str, ulong length, CHARSET_INFO *cs)
{
/* TODO: Fix this for binary handling by making use of
buffer_type..
*/
str_value.append(str,length);
void Item_param::set_longdata(const char *str, ulong length)
{
str_value.append(str,length);
long_data_supplied= 1;
}
@ -438,6 +435,7 @@ bool Item::fix_fields(THD *thd,
struct st_table_list *list,
Item ** ref)
{
fixed= 1;
return 0;
}
@ -459,23 +457,48 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
*/
SELECT_LEX *last= 0;
Item **refer= (Item **)not_found_item;
// Prevent using outer fields in subselects, that is not supported now
if (thd->lex.current_select->linkage != DERIVED_TABLE_TYPE)
for (SELECT_LEX *sl= thd->lex.current_select->outer_select();
sl;
sl= sl->outer_select())
{
if ((tmp= find_field_in_tables(thd, this,
(last= sl)->get_table_list(),
0)) != not_found_field)
break;
if((refer= find_item_in_list(this, (last= sl)->item_list,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
}
if (!tmp)
return -1;
else if (tmp == not_found_field)
else if (!refer)
return 1;
else if (tmp == not_found_field && refer == (Item **)not_found_item)
{
// call to return error code
find_field_in_tables(thd, this, tables, 1);
return -1;
}
else if (refer != (Item **)not_found_item)
{
Item_ref *r;
*ref= r= new Item_ref((char *)db_name, (char *)table_name,
(char *)field_name);
if (!r)
return 1;
int res;
if ((res= r->fix_fields(thd, tables, ref)))
return res;
r->depended_from= last;
thd->lex.current_select->mark_as_dependent(last);
thd->add_possible_loop(r);
return 0;
}
else
{
depended_from= last;
@ -507,6 +530,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 1;
return (*ref)->fix_fields(thd, tables, ref);
}
fixed= 1;
return 0;
}
@ -885,6 +909,19 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
}
if (((*ref)->with_sum_func &&
(depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
thd->lex.current_select->select_lex()->having_fix_field))) ||
!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
((*ref)->with_sum_func?
"reference on group function":
"forward reference in item list"));
return 1;
}
fixed= 1;
return 0;
}

View file

@ -46,6 +46,7 @@ public:
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
my_bool with_sum_func;
my_bool fixed; /* If item fixed with fix_fields */
// alloc & destruct is done as start of select using sql_alloc
Item();
@ -186,8 +187,8 @@ public:
Item_param(char *name_par=0)
{
name= name_par ? name_par : (char*) "?";
long_data_supplied = false;
item_type = STRING_ITEM;
long_data_supplied= false;
item_type= STRING_ITEM;
item_result_type = STRING_RESULT;
}
enum Type type() const { return item_type; }
@ -199,12 +200,13 @@ public:
void set_null();
void set_int(longlong i);
void set_double(double i);
void set_value(const char *str, uint length, CHARSET_INFO *cs);
void set_long_str(const char *str, ulong length, CHARSET_INFO *cs);
void set_long_binary(const char *str, ulong length, CHARSET_INFO *cs);
void set_longdata(const char *str, ulong length, CHARSET_INFO *cs);
void set_value(const char *str, uint length);
void set_long_str(const char *str, ulong length);
void set_long_binary(const char *str, ulong length);
void set_longdata(const char *str, ulong length);
void set_long_end();
void reset() {}
void (*setup_param_func)(Item_param *param, uchar **pos);
enum Item_result result_type () const
{ return item_result_type; }
Item *new_item() { return new Item_param(name); }
@ -401,8 +403,8 @@ public:
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
{ return (*ref)->eq(item, binary_cmp); }
~Item_ref() { if (ref) delete *ref; }
{ return ref && (*ref)->eq(item, binary_cmp); }
~Item_ref() { if (ref && (*ref) != this) delete *ref; }
double val()
{
double tmp=(*ref)->val_result();

View file

@ -1160,6 +1160,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (thd)
thd->cond_count+=list.elements;
fix_length_and_dec();
fixed= 1;
return 0;
}
@ -1485,6 +1486,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
else
maybe_null=1;
fixed= 1;
return 0;
}

View file

@ -123,6 +123,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
}
fix_length_and_dec();
fixed= 1;
return 0;
}

View file

@ -754,6 +754,7 @@ public:
bool res= udf.fix_fields(thd, tables, this, arg_count, args);
used_tables_cache= udf.used_tables_cache;
const_item_cache= udf.const_item_cache;
fixed= 1;
return res;
}
Item_result result_type () const { return udf.result_type(); }

View file

@ -2079,6 +2079,7 @@ bool Item_func_conv_charset::fix_fields(THD *thd,struct st_table_list *tables, I
const_item_cache=args[0]->const_item();
set_charset(conv_charset);
fix_length_and_dec();
fixed= 1;
return 0;
}
@ -2113,6 +2114,7 @@ bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables,
used_tables_cache=args[0]->used_tables();
const_item_cache=args[0]->const_item();
fix_length_and_dec();
fixed= 1;
return 0;
}

View file

@ -92,6 +92,7 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
fix_length_and_dec();
}
fixed= 1;
return res;
}

View file

@ -135,6 +135,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
fixed= 1;
return 0;
}
@ -165,6 +166,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
fixed= 1;
return 0;
}

View file

@ -384,6 +384,7 @@ public:
const char *func_name() const { return udf.name(); }
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
fixed= 1;
return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }

View file

@ -43,5 +43,9 @@ public:
bool add() { return 0; }
void reset_field() {}
void update_field(int offset) {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { return 0;}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
fixed= 1;
return 0;
}
};

View file

@ -513,7 +513,7 @@ int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
/* sql_prepare.cc */
int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used);
int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key);
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used);
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
void mysql_stmt_execute(THD *thd, char *packet);

View file

@ -254,4 +254,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -248,4 +248,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -256,4 +256,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -250,4 +250,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -248,4 +248,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -247,4 +247,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -247,4 +247,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -247,4 +247,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -247,4 +247,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -249,4 +249,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -250,3 +250,4 @@
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Reference '%-.64s' not supported (%s)",

View file

@ -248,4 +248,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ",
"Converting column '%s' from %s to %s"
"Преобразование поля '%s' из %s в %s",
"Ссылка '%-.64s' не поддерживается (%s)",

View file

@ -241,4 +241,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -253,4 +253,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -246,4 +246,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
"Converting column '%s' from %s to %s"
"Converting column '%s' from %s to %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -245,4 +245,5 @@
"Okänd PREPARED STATEMENT id (%ld) var given till %s",
"Hjälp databasen finns inte eller är skadad",
"Syklisk referens i subselect",
"Konvertar kolumn '%s' från %s till %s"
"Konvertar kolumn '%s' från %s till %s",
"Reference '%-.64s' not supported (%s)",

View file

@ -250,4 +250,5 @@
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"ãÉËÌiÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ÐiÄÚÁÐÉÔ",
"Converting column '%s' from %s to %s"
"Перетворення стовбца '%s' з %s у %s",
"Посилання '%-.64s' не пiдтримуется (%s)",

View file

@ -2225,8 +2225,10 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
thd->cond_count=0;
thd->allow_sum_func=0;
thd->cond_count= 0;
bool save_allow_sum_func= thd->allow_sum_func;
thd->allow_sum_func= 0;
if (*conds)
{
thd->where="where clause";
@ -2299,6 +2301,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table->on_expr=and_conds(table->on_expr,cond_and);
}
}
thd->allow_sum_func= save_allow_sum_func;
DBUG_RETURN(test(thd->fatal_error));
}

View file

@ -325,7 +325,7 @@ typedef struct st_prep_stmt
uint param_count;
uint last_errno;
char last_error[MYSQL_ERRMSG_SIZE];
bool error_in_prepare, long_data_used;
bool error_in_prepare, long_data_used, param_inited;
} PREP_STMT;
@ -510,7 +510,6 @@ public:
bool safe_to_cache_query;
bool volatile killed;
bool prepare_command;
Item_param *params; // Pointer to array of params
/*
If we do a purge of binary logs, log index info of the threads

View file

@ -127,7 +127,7 @@ static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
{
List<Item> field_list;
DBUG_ENTER("mysqld_show_errors");
DBUG_ENTER("mysqld_show_warnings");
field_list.push_back(new Item_empty_string("Level", 7));
field_list.push_back(new Item_int("Code",0,4));

View file

@ -30,10 +30,11 @@ Prepare:
Prepare-execute:
- Server gets the command 'COM_EXECUTE' to execute the
previously prepared query.
- If there is are any parameters, then replace the markers with the
data supplied by client with the following format:
[types_specified(0/1)][type][length][data] .. [type][length]..
previously prepared query. If there is any param markers; then client
will send the data in the following format:
[null_bits][types_specified(0/1)][[length][data]][[length][data] .. [length][data].
- Replace the param items with this new data. If it is a first execute
or types altered by client; then setup the conversion routines.
- Execute the query without re-parsing and send back the results
to client
@ -53,33 +54,9 @@ Long data handling:
#include <assert.h> // for DEBUG_ASSERT()
#include <m_ctype.h> // for isspace()
extern int yyparse(void);
static ulong get_param_length(uchar **packet);
static uint get_buffer_type(uchar **packet);
static bool param_is_null(uchar **packet);
static bool setup_param_fields(THD *thd,List<Item> &params);
static uchar* setup_param_field(Item_param *item_param, uchar *pos,
uint buffer_type);
static void setup_longdata_field(Item_param *item_param, uchar *pos);
static bool setup_longdata(THD *thd,List<Item> &params);
static bool send_prepare_results(PREP_STMT *stmt);
static bool parse_prepare_query(PREP_STMT *stmt, char *packet, uint length);
static bool mysql_send_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
List<Item> &fields,
List<List_item> &values_list,
thr_lock_type lock_type);
static bool mysql_test_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
List<Item> &fields,
List<List_item> &values_list,
thr_lock_type lock_type);
static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
COND *conds,thr_lock_type lock_type);
static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
List<Item> &fields, List<Item> &values,
COND *conds, ORDER *order, ORDER *group,
Item *having,thr_lock_type lock_type);
#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
extern int yyparse(void);
/*
Find prepared statement in thd
@ -114,9 +91,9 @@ static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id,
Compare two prepared statements; Used to find a prepared statement
*/
int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used)
int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key)
{
return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1;
return (stmt->stmt_id == *key) ? 0 : (stmt->stmt_id < *key) ? -1 : 1;
}
@ -132,22 +109,23 @@ int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used)
*/
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used)
{
free_root(&stmt->mem_root, MYF(0));
{
free_items(stmt->free_list);
free_root(&stmt->mem_root, MYF(0));
}
/*
Send prepared stmt info to client after prepare
*/
bool send_prep_stmt(PREP_STMT *stmt, uint columns)
static bool send_prep_stmt(PREP_STMT *stmt, uint columns)
{
NET *net=&stmt->thd->net;
char buff[8];
int4store(buff, stmt->stmt_id);
int2store(buff+4, columns);
int2store(buff+6, stmt->param_count);
return my_net_write(&stmt->thd->net, buff, sizeof(buff));
return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
}
/*
@ -156,43 +134,15 @@ bool send_prep_stmt(PREP_STMT *stmt, uint columns)
TODO: Not yet ready
*/
bool send_item_params(PREP_STMT *stmt)
static bool send_item_params(PREP_STMT *stmt)
{
#if 0
char buff[1];
buff[0]=0;
return my_net_write(&stmt->thd->net, buff, sizeof(buff));
}
/*
Read the buffer type, this happens only first time
*/
static uint get_buffer_type(uchar **packet)
{
reg1 uchar *pos= *packet;
(*packet)+= 2;
return (uint) uint2korr(pos);
}
/*
Check for NULL param data
RETURN VALUES
0 Value was not NULL
1 Value was NULL
*/
static bool param_is_null(uchar **packet)
{
reg1 uchar *pos= *packet;
if (*pos == 251)
{
(*packet)++;
if (my_net_write(&stmt->thd->net, buff, sizeof(buff)))
return 1;
}
send_eof(stmt->thd);
#endif
return 0;
}
@ -222,60 +172,103 @@ static ulong get_param_length(uchar **packet)
(*packet)+=9; // Must be 254 when here
return (ulong) uint4korr(pos+1);
}
/*
Setup param conversion routines
/*
Read and return the data for parameters supplied by client
setup_param_xx()
param Parameter Item
pos Input data buffer
All these functions reads the data from pos and sets up that data
through 'param' and advances the buffer position to predifined
length position.
Make a note that the NULL handling is examined at first execution
(i.e. when input types altered) and for all subsequent executions
we don't read any values for this.
RETURN VALUES
*/
static uchar* setup_param_field(Item_param *item_param,
uchar *pos, uint buffer_type)
static void setup_param_tiny(Item_param *param, uchar **pos)
{
if (param_is_null(&pos))
{
item_param->set_null();
return(pos);
}
switch (buffer_type) {
param->set_int((longlong)(**pos));
*pos+= 1;
}
static void setup_param_short(Item_param *param, uchar **pos)
{
param->set_int((longlong)sint2korr(*pos));
*pos+= 2;
}
static void setup_param_int32(Item_param *param, uchar **pos)
{
param->set_int((longlong)sint4korr(*pos));
*pos+= 4;
}
static void setup_param_int64(Item_param *param, uchar **pos)
{
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
}
static void setup_param_float(Item_param *param, uchar **pos)
{
float data;
float4get(data,*pos);
param->set_double((double) data);
*pos+= 4;
}
static void setup_param_double(Item_param *param, uchar **pos)
{
double data;
float8get(data,*pos);
param->set_double((double) data);
*pos+= 8;
}
static void setup_param_str(Item_param *param, uchar **pos)
{
ulong len=get_param_length(pos);
param->set_value((const char *)*pos, len);
*pos+=len;
}
static void setup_param_functions(Item_param *param, uchar read_pos)
{
switch (read_pos) {
case FIELD_TYPE_TINY:
item_param->set_int((longlong)(*pos));
pos += 1;
param->setup_param_func= setup_param_tiny;
param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_SHORT:
item_param->set_int((longlong)sint2korr(pos));
pos += 2;
break;
case FIELD_TYPE_INT24:
item_param->set_int((longlong)sint4korr(pos));
pos += 3;
param->setup_param_func= setup_param_short;
param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_LONG:
item_param->set_int((longlong)sint4korr(pos));
pos += 4;
param->setup_param_func= setup_param_int32;
param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_LONGLONG:
item_param->set_int((longlong)sint8korr(pos));
pos += 8;
param->setup_param_func= setup_param_int64;
param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_FLOAT:
float data;
float4get(data,pos);
item_param->set_double((double) data);
pos += 4;
param->setup_param_func= setup_param_float;
param->item_result_type = REAL_RESULT;
break;
case FIELD_TYPE_DOUBLE:
double j;
float8get(j,pos)
item_param->set_double(j);
pos += 8;
param->setup_param_func= setup_param_double;
param->item_result_type = REAL_RESULT;
break;
default:
{
ulong len=get_param_length(&pos);
item_param->set_value((const char*)pos,len,current_thd->thd_charset);
pos+=len;
}
param->setup_param_func= setup_param_str;
param->item_result_type = STRING_RESULT;
}
return(pos);
}
/*
@ -283,42 +276,46 @@ static uchar* setup_param_field(Item_param *item_param,
from client ..
*/
static bool setup_param_fields(THD *thd, PREP_STMT *stmt)
{
DBUG_ENTER("setup_param_fields");
#ifdef READY_TO_BE_USED
Item_param *item_param;
ulong param_count=0;
uchar *pos=(uchar*) thd->net.read_pos+1;// skip command type
static bool setup_params_data(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
List<Item> &params= thd->lex.param_list;
List_iterator<Item> param_iterator(params);
Item_param *param;
DBUG_ENTER("setup_params_data");
if (*pos++) // No types supplied, read only param data
{
while ((item_param=(Item_param *)it++) &&
(param_count++ < stmt->param_count))
{
if (item_param->long_data_supplied)
continue;
uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header
uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits
ulong param_no;
if (!(pos=setup_param_field(item_param,pos,item_param->buffer_type)))
DBUG_RETURN(1);
if (*read_pos++) //types supplied / first execute
{
/*
First execute or types altered by the client, setup the
conversion routines for all parameters (one time)
*/
while ((param= (Item_param *)param_iterator++))
{
if (!param->long_data_supplied)
{
setup_param_functions(param,*read_pos);
read_pos+= 2;
}
}
}
else // Types supplied, read and store it along with param data
param_iterator.rewind();
}
param_no= 0;
while ((param= (Item_param *)param_iterator++))
{
while ((item_param=(Item_param *)it++) &&
(param_count++ < thd->param_count))
if (!param->long_data_supplied)
{
if (item_param->long_data_supplied)
continue;
if (!(pos=setup_param_field(item_param,pos,
item_param->buffer_type=
(enum_field_types) get_buffer_type(&pos))))
DBUG_RETURN(1);
if (IS_PARAM_NULL(pos,param_no))
param->maybe_null=param->null_value=1;
else
param->setup_param_func(param,&read_pos);
}
param_no++;
}
#endif
DBUG_RETURN(0);
}
@ -379,8 +376,7 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields,
static bool mysql_test_insert_fields(PREP_STMT *stmt,
TABLE_LIST *table_list,
List<Item> &fields,
List<List_item> &values_list,
thr_lock_type lock_type)
List<List_item> &values_list)
{
THD *thd= stmt->thd;
TABLE *table;
@ -388,7 +384,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
List_item *values;
DBUG_ENTER("mysql_test_insert_fields");
if (!(table = open_ltable(thd,table_list,lock_type)))
if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1);
if ((values= its++))
@ -431,13 +427,13 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
COND *conds, thr_lock_type lock_type)
COND *conds)
{
THD *thd= stmt->thd;
TABLE *table;
DBUG_ENTER("mysql_test_upd_fields");
if (!(table = open_ltable(thd,table_list,lock_type)))
if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1);
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) ||
@ -469,7 +465,7 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
List<Item> &fields, List<Item> &values,
COND *conds, ORDER *order, ORDER *group,
Item *having, thr_lock_type lock_type)
Item *having)
{
TABLE *table;
bool hidden_group_fields;
@ -477,7 +473,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
List<Item> all_fields(fields);
DBUG_ENTER("mysql_test_select_fields");
if (!(table = open_ltable(thd,tables,lock_type)))
if (!(table = open_ltable(thd,tables,tables->lock_type)))
DBUG_RETURN(1);
thd->used_tables=0; // Updated by setup_fields
@ -550,21 +546,19 @@ static bool send_prepare_results(PREP_STMT *stmt)
case SQLCOM_INSERT:
if (mysql_test_insert_fields(stmt, tables, lex->field_list,
lex->many_values, lex->lock_option))
lex->many_values))
goto abort;
break;
case SQLCOM_UPDATE:
if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
lex->value_list, select_lex->where,
lex->lock_option))
lex->value_list, select_lex->where))
goto abort;
break;
case SQLCOM_DELETE:
if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
lex->value_list, select_lex->where,
lex->lock_option))
lex->value_list, select_lex->where))
goto abort;
break;
@ -572,8 +566,7 @@ static bool send_prepare_results(PREP_STMT *stmt)
if (mysql_test_select_fields(stmt, tables, select_lex->item_list,
lex->value_list, select_lex->where,
(ORDER*) select_lex->order_list.first,
(ORDER*) select_lex->group_list.first,
select_lex->having, lex->lock_option))
(ORDER*) select_lex->group_list.first, select_lex->having))
goto abort;
break;
@ -583,6 +576,8 @@ static bool send_prepare_results(PREP_STMT *stmt)
Rest fall through to default category, no parsing
for non-DML statements
*/
if (send_prep_stmt(stmt, 0))
goto abort;
}
}
DBUG_RETURN(0);
@ -597,7 +592,7 @@ abort:
*/
static bool parse_prepare_query(PREP_STMT *stmt,
char *packet, uint length)
char *packet, uint length)
{
bool error= 1;
THD *thd= stmt->thd;
@ -607,6 +602,7 @@ static bool parse_prepare_query(PREP_STMT *stmt,
mysql_init_query(thd);
thd->prepare_command=true;
thd->safe_to_cache_query= 0;
thd->lex.param_count=0;
LEX *lex=lex_start(thd, (uchar*) packet, length);
if (!yyparse() && !thd->fatal_error)
@ -615,6 +611,25 @@ static bool parse_prepare_query(PREP_STMT *stmt,
DBUG_RETURN(error);
}
/*
Initialize parameter items in statement
*/
static bool init_param_items(THD *thd, PREP_STMT *stmt)
{
#if TO_BE_TESTED
Item_param **to;
if (!(to= (Item_param *)
my_malloc(sizeof(Item_param*) * stmt->param_count, MYF(MY_WME))))
return 1;
List<Item> &params= thd->lex.param_list;
List_iterator<Item> param_iterator(params);
while ((to++ = (Item_param *)param_iterator++))
{
DBUG_PRINT("info",("param: %lx", to));
}
return 0;
#endif
}
/*
Parse the query and send the total number of parameters
@ -648,10 +663,15 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
goto err;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
stmt.mem_root= thd->mem_root;
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
#if 0
if (init_param_items(thd, &stmt))
goto err;
#endif
stmt.mem_root= thd->mem_root;
tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0);
thd->mem_root= thd_root; // restore main mem_root
thd->last_prepared_stmt= &stmt;
DBUG_RETURN(0);
err:
@ -685,15 +705,13 @@ void mysql_stmt_execute(THD *thd, char *packet)
/* Check if we got an error when sending long data */
if (stmt->error_in_prepare)
{
send_error(thd);
send_error(thd, stmt->last_errno, stmt->last_error);
DBUG_VOID_RETURN;
}
if (stmt->param_count && setup_param_fields(thd, stmt))
if (stmt->param_count && setup_params_data(stmt))
DBUG_VOID_RETURN;
MEM_ROOT thd_root= thd->mem_root;
thd->mem_root = thd->con_root;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
@ -703,12 +721,12 @@ void mysql_stmt_execute(THD *thd, char *packet)
mysql_delete(), mysql_update() and mysql_select() to not to
have re-check on setup_* and other things ..
*/
mysql_execute_command(thd);
mysql_execute_command(stmt->thd);
thd->last_prepared_stmt= stmt;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
thd->mem_root= thd_root;
DBUG_VOID_RETURN;
}
@ -768,8 +786,10 @@ void mysql_stmt_close(THD *thd, char *packet)
send_error(thd);
DBUG_VOID_RETURN;
}
stmt->param= 0;
my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
/* Will call free_prep_stmt() */
tree_delete(&thd->prepared_statements, (void*) stmt, NULL);
tree_delete(&thd->prepared_statements, (void*) &stmt, (void *)0);
thd->last_prepared_stmt=0;
DBUG_VOID_RETURN;
}
@ -800,17 +820,16 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
DBUG_ENTER("mysql_stmt_get_longdata");
/* The following should never happen */
if (packet_length < 9)
if (packet_length < MYSQL_LONG_DATA_HEADER+1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
DBUG_VOID_RETURN;
}
pos++; // skip command type at first position
ulong stmt_id= uint4korr(pos);
uint param_number= uint2korr(pos+4);
uint param_type= uint2korr(pos+6);
pos+=8; // Point to data
pos+=MYSQL_LONG_DATA_HEADER; // Point to data
if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
{
@ -829,7 +848,8 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
DBUG_VOID_RETURN;
}
stmt->param[param_number].set_longdata(pos, packet_length-9, current_thd->thd_charset);
stmt->param[param_number].set_longdata(pos, packet_length-9);
stmt->long_data_used= 1;
DBUG_VOID_RETURN;
}

File diff suppressed because it is too large Load diff