mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 02:30:06 +01:00
Fix to support update + bianry logs with prepared statements (Dynamic query)
sql/item.cc: query_val_str to return param item value in string format sql/item.h: Misc defination changes for Item_param sql/sql_class.h: Changes for PREP_STMT sql/sql_string.cc: Duplicate String::replace to take char * and length as arguments sql/sql_yacc.yy: Change to take param marker position to Item_param as an argument sql/sql_prepare.cc: Fix for binary + update logs sql/sql_string.h: Added new replace()
This commit is contained in:
parent
1e8cc909de
commit
f2f748c631
7 changed files with 212 additions and 35 deletions
73
sql/item.cc
73
sql/item.cc
|
@ -542,6 +542,79 @@ String *Item_param::val_str(String* str)
|
||||||
return (String*) &str_value;
|
return (String*) &str_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return Param item values in string format, for generating the dynamic
|
||||||
|
query used in update/binary logs
|
||||||
|
*/
|
||||||
|
|
||||||
|
String *Item_param::query_val_str(String* str)
|
||||||
|
{
|
||||||
|
switch (item_result_type) {
|
||||||
|
case INT_RESULT:
|
||||||
|
str->set(int_value, default_charset());
|
||||||
|
break;
|
||||||
|
case REAL_RESULT:
|
||||||
|
set->set(real_value, 2, default_charset());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str->set("'", 1, default_charset());
|
||||||
|
|
||||||
|
if (!item_is_time)
|
||||||
|
{
|
||||||
|
str->append(str_value);
|
||||||
|
const char *from= str->ptr();
|
||||||
|
uint32 length= 1;
|
||||||
|
|
||||||
|
// Escape misc cases
|
||||||
|
char *to= (char *)from, *end= (char *)to+str->length();
|
||||||
|
for (to++; to != end ; length++, to++)
|
||||||
|
{
|
||||||
|
switch(*to) {
|
||||||
|
case '\'':
|
||||||
|
case '"':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case '\\': // TODO: Add remaining ..
|
||||||
|
str->replace(length,0,"\\",1);
|
||||||
|
to++; end++; length++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buff[25];
|
||||||
|
|
||||||
|
switch (ltime.time_type) {
|
||||||
|
case TIMESTAMP_NONE:
|
||||||
|
break;
|
||||||
|
case TIMESTAMP_DATE:
|
||||||
|
sprintf(buff, "%04d-%02d-%02d",
|
||||||
|
ltime.year,ltime.month,ltime.day);
|
||||||
|
str->append(buff, 10);
|
||||||
|
break;
|
||||||
|
case TIMESTAMP_FULL:
|
||||||
|
sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||||
|
ltime.year,ltime.month,ltime.day,
|
||||||
|
ltime.hour,ltime.minute,ltime.second));
|
||||||
|
str->append(buff, 19);
|
||||||
|
break;
|
||||||
|
case TIMESTAMP_TIME:
|
||||||
|
{
|
||||||
|
sprintf(buff, "%02d:%02d:%02d",
|
||||||
|
ltime.hour,ltime.minute,ltime.second));
|
||||||
|
str->append(buff, 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str->append("'");
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
/* End of Item_param related */
|
/* End of Item_param related */
|
||||||
|
|
||||||
|
|
||||||
|
|
13
sql/item.h
13
sql/item.h
|
@ -239,15 +239,17 @@ public:
|
||||||
enum Type item_type;
|
enum Type item_type;
|
||||||
enum enum_field_types buffer_type;
|
enum enum_field_types buffer_type;
|
||||||
bool item_is_time;
|
bool item_is_time;
|
||||||
my_bool long_data_supplied;
|
bool long_data_supplied;
|
||||||
|
uint pos_in_query;
|
||||||
|
|
||||||
Item_param(char *name_par=0)
|
Item_param::Item_param(uint position)
|
||||||
{
|
{
|
||||||
name= name_par ? name_par : (char*) "?";
|
name= (char*) "?";
|
||||||
long_data_supplied= false;
|
pos_in_query= position;
|
||||||
item_type= STRING_ITEM;
|
item_type= STRING_ITEM;
|
||||||
item_result_type = STRING_RESULT;
|
item_result_type = STRING_RESULT;
|
||||||
item_is_time= false;
|
item_is_time= false;
|
||||||
|
long_data_supplied= false;
|
||||||
}
|
}
|
||||||
enum Type type() const { return item_type; }
|
enum Type type() const { return item_type; }
|
||||||
double val();
|
double val();
|
||||||
|
@ -268,8 +270,9 @@ public:
|
||||||
void (*setup_param_func)(Item_param *param, uchar **pos);
|
void (*setup_param_func)(Item_param *param, uchar **pos);
|
||||||
enum Item_result result_type () const
|
enum Item_result result_type () const
|
||||||
{ return item_result_type; }
|
{ return item_result_type; }
|
||||||
|
String *query_val_str(String *str);
|
||||||
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
|
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
|
||||||
Item *new_item() { return new Item_param(name); }
|
Item *new_item() { return new Item_param(pos_in_query); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_int :public Item
|
class Item_int :public Item
|
||||||
|
|
|
@ -324,11 +324,14 @@ typedef struct st_prep_stmt
|
||||||
Item_param **param;
|
Item_param **param;
|
||||||
Item *free_list;
|
Item *free_list;
|
||||||
MEM_ROOT mem_root;
|
MEM_ROOT mem_root;
|
||||||
|
String *query;
|
||||||
ulong stmt_id;
|
ulong stmt_id;
|
||||||
uint param_count;
|
uint param_count;
|
||||||
uint last_errno;
|
uint last_errno;
|
||||||
char last_error[MYSQL_ERRMSG_SIZE];
|
char last_error[MYSQL_ERRMSG_SIZE];
|
||||||
bool error_in_prepare, long_data_used;
|
bool error_in_prepare, long_data_used;
|
||||||
|
bool log_full_query;
|
||||||
|
bool (*setup_params)(st_prep_stmt *stmt, uchar *pos, uchar *read_pos);
|
||||||
} PREP_STMT;
|
} PREP_STMT;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,10 @@ Long data handling:
|
||||||
|
|
||||||
#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
|
#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
|
||||||
|
|
||||||
|
#define STMT_QUERY_LOG_LENGTH 8192
|
||||||
|
|
||||||
extern int yyparse(void *thd);
|
extern int yyparse(void *thd);
|
||||||
|
static String null_string("NULL", 4, default_charset_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find prepared statement in thd
|
Find prepared statement in thd
|
||||||
|
@ -129,6 +132,8 @@ 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)
|
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used)
|
||||||
{
|
{
|
||||||
my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
|
my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
|
||||||
|
if (stmt->query)
|
||||||
|
stmt->query->free();
|
||||||
free_items(stmt->free_list);
|
free_items(stmt->free_list);
|
||||||
free_root(&stmt->mem_root, MYF(0));
|
free_root(&stmt->mem_root, MYF(0));
|
||||||
}
|
}
|
||||||
|
@ -374,8 +379,8 @@ static void setup_param_functions(Item_param *param, uchar param_type)
|
||||||
param->setup_param_func= setup_param_date;
|
param->setup_param_func= setup_param_date;
|
||||||
param->item_result_type= STRING_RESULT;
|
param->item_result_type= STRING_RESULT;
|
||||||
break;
|
break;
|
||||||
case FIELD_TYPE_DATETIME:
|
case MYSQL_TYPE_DATETIME:
|
||||||
case FIELD_TYPE_TIMESTAMP:
|
case MYSQL_TYPE_TIMESTAMP:
|
||||||
param->setup_param_func= setup_param_datetime;
|
param->setup_param_func= setup_param_datetime;
|
||||||
param->item_result_type= STRING_RESULT;
|
param->item_result_type= STRING_RESULT;
|
||||||
break;
|
break;
|
||||||
|
@ -386,10 +391,82 @@ static void setup_param_functions(Item_param *param, uchar param_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update the parameter markers by reading the data
|
Update the parameter markers by reading data from client packet
|
||||||
from client ..
|
and if binary/update log is set, generate the valid query.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
|
||||||
|
{
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
List<Item> ¶ms= thd->lex.param_list;
|
||||||
|
List_iterator<Item> param_iterator(params);
|
||||||
|
Item_param *param;
|
||||||
|
DBUG_ENTER("insert_params_withlog");
|
||||||
|
|
||||||
|
String str, *res, *query= new String(stmt->query->alloced_length());
|
||||||
|
query->copy(*stmt->query);
|
||||||
|
|
||||||
|
ulong param_no= 0;
|
||||||
|
uint32 length= 0;
|
||||||
|
|
||||||
|
while ((param= (Item_param *)param_iterator++))
|
||||||
|
{
|
||||||
|
if (param->long_data_supplied)
|
||||||
|
res= param->query_val_str(&str);
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IS_PARAM_NULL(pos,param_no))
|
||||||
|
{
|
||||||
|
param->maybe_null= param->null_value= 1;
|
||||||
|
res= &null_string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
param->maybe_null= param->null_value= 0;
|
||||||
|
param->setup_param_func(param,&read_pos);
|
||||||
|
res= param->query_val_str(&str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (query->replace(param->pos_in_query+length, 1, *res))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
length+= res->length()-1;
|
||||||
|
param_no++;
|
||||||
|
}
|
||||||
|
if (alloc_query(stmt->thd, (char *)query->ptr(), query->length()+1))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
query->free();
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool insert_params(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
|
||||||
|
{
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
List<Item> ¶ms= thd->lex.param_list;
|
||||||
|
List_iterator<Item> param_iterator(params);
|
||||||
|
Item_param *param;
|
||||||
|
DBUG_ENTER("insert_params");
|
||||||
|
|
||||||
|
ulong param_no= 0;
|
||||||
|
while ((param= (Item_param *)param_iterator++))
|
||||||
|
{
|
||||||
|
if (!param->long_data_supplied)
|
||||||
|
{
|
||||||
|
if (IS_PARAM_NULL(pos,param_no))
|
||||||
|
param->maybe_null= param->null_value= 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
param->maybe_null= param->null_value= 0;
|
||||||
|
param->setup_param_func(param,&read_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
param_no++;
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
static bool setup_params_data(PREP_STMT *stmt)
|
static bool setup_params_data(PREP_STMT *stmt)
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
|
@ -418,21 +495,7 @@ static bool setup_params_data(PREP_STMT *stmt)
|
||||||
}
|
}
|
||||||
param_iterator.rewind();
|
param_iterator.rewind();
|
||||||
}
|
}
|
||||||
ulong param_no= 0;
|
stmt->setup_params(stmt,pos,read_pos);
|
||||||
while ((param= (Item_param *)param_iterator++))
|
|
||||||
{
|
|
||||||
if (!param->long_data_supplied)
|
|
||||||
{
|
|
||||||
if (IS_PARAM_NULL(pos,param_no))
|
|
||||||
param->maybe_null= param->null_value= 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
param->maybe_null= param->null_value= 0;
|
|
||||||
param->setup_param_func(param,&read_pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
param_no++;
|
|
||||||
}
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,21 +770,42 @@ static bool parse_prepare_query(PREP_STMT *stmt,
|
||||||
|
|
||||||
static bool init_param_items(PREP_STMT *stmt)
|
static bool init_param_items(PREP_STMT *stmt)
|
||||||
{
|
{
|
||||||
List<Item> ¶ms= stmt->thd->lex.param_list;
|
THD *thd= stmt->thd;
|
||||||
|
List<Item> ¶ms= thd->lex.param_list;
|
||||||
Item_param **to;
|
Item_param **to;
|
||||||
|
uint32 length= thd->query_length;
|
||||||
|
|
||||||
stmt->lex= stmt->thd->lex;
|
stmt->lex= thd->lex;
|
||||||
|
|
||||||
|
if (mysql_bin_log.is_open() || mysql_update_log.is_open())
|
||||||
|
{
|
||||||
|
stmt->log_full_query= 1;
|
||||||
|
stmt->setup_params= insert_params_withlog;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stmt->setup_params= insert_params; // not fully qualified query
|
||||||
|
|
||||||
if (!stmt->param_count)
|
if (!stmt->param_count)
|
||||||
stmt->param= (Item_param **)0;
|
stmt->param= (Item_param **)0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(stmt->param= to= (Item_param **)
|
if (!(stmt->param= to= (Item_param **)
|
||||||
my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
|
my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
|
||||||
MYF(MY_WME))))
|
MYF(MY_WME))))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (stmt->log_full_query)
|
||||||
|
{
|
||||||
|
length= thd->query_length+(stmt->param_count*2)+1;
|
||||||
|
|
||||||
|
if ( length < STMT_QUERY_LOG_LENGTH )
|
||||||
|
length= STMT_QUERY_LOG_LENGTH;
|
||||||
|
}
|
||||||
List_iterator<Item> param_iterator(params);
|
List_iterator<Item> param_iterator(params);
|
||||||
while ((*(to++)= (Item_param *)param_iterator++));
|
while ((*(to++)= (Item_param *)param_iterator++));
|
||||||
}
|
}
|
||||||
|
stmt->query= new String(length);
|
||||||
|
stmt->query->copy(thd->query, thd->query_length, default_charset_info);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,6 +825,12 @@ static void init_stmt_execute(PREP_STMT *stmt)
|
||||||
*/
|
*/
|
||||||
for (; tables ; tables= tables->next)
|
for (; tables ; tables= tables->next)
|
||||||
tables->table= 0; //safety - nasty init
|
tables->table= 0; //safety - nasty init
|
||||||
|
|
||||||
|
if (!(stmt->log_full_query && stmt->param_count))
|
||||||
|
{
|
||||||
|
thd->query= stmt->query->c_ptr();
|
||||||
|
thd->query_length= stmt->query->length();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -508,14 +508,20 @@ skipp:
|
||||||
|
|
||||||
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
|
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
|
||||||
{
|
{
|
||||||
long diff = (long) to.length()-(long) arg_length;
|
return replace(offset,arg_length,to.ptr(),to.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::replace(uint32 offset,uint32 arg_length,
|
||||||
|
const char *to,uint32 length)
|
||||||
|
{
|
||||||
|
long diff = (long) length-(long) arg_length;
|
||||||
if (offset+arg_length <= str_length)
|
if (offset+arg_length <= str_length)
|
||||||
{
|
{
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
{
|
{
|
||||||
if (to.length())
|
if (length)
|
||||||
memcpy(Ptr+offset,to.ptr(),to.length());
|
memcpy(Ptr+offset,to,length);
|
||||||
bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
|
bmove(Ptr+offset+length,Ptr+offset+arg_length,
|
||||||
str_length-offset-arg_length);
|
str_length-offset-arg_length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -527,14 +533,15 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
|
||||||
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
|
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
|
||||||
str_length-offset-arg_length);
|
str_length-offset-arg_length);
|
||||||
}
|
}
|
||||||
if (to.length())
|
if (length)
|
||||||
memcpy(Ptr+offset,to.ptr(),to.length());
|
memcpy(Ptr+offset,to,length);
|
||||||
}
|
}
|
||||||
str_length+=(uint32) diff;
|
str_length+=(uint32) diff;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// added by Holyfoot for "geometry" needs
|
// added by Holyfoot for "geometry" needs
|
||||||
int String::reserve(uint32 space_needed, uint32 grow_by)
|
int String::reserve(uint32 space_needed, uint32 grow_by)
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,6 +186,7 @@ public:
|
||||||
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
||||||
int strstr_case(const String &s,uint32 offset=0);
|
int strstr_case(const String &s,uint32 offset=0);
|
||||||
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
|
||||||
|
bool replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
|
||||||
bool replace(uint32 offset,uint32 arg_length,const String &to);
|
bool replace(uint32 offset,uint32 arg_length,const String &to);
|
||||||
inline bool append(char chr)
|
inline bool append(char chr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3932,7 +3932,7 @@ param_marker:
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (YYTHD->prepare_command)
|
if (YYTHD->prepare_command)
|
||||||
{
|
{
|
||||||
lex->param_list.push_back($$=new Item_param());
|
lex->param_list.push_back($$=new Item_param((uint)(lex->tok_start-(uchar *)YYTHD->query)));
|
||||||
lex->param_count++;
|
lex->param_count++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Add table
Reference in a new issue