Commit 15cc92ca authored by jcole@mugatu.jcole.us's avatar jcole@mugatu.jcole.us

Added LOCAL INFILE callback function support.

parent de09e55b
......@@ -63,6 +63,7 @@ jani@ua167d18.elisa.omakaista.fi
jani@ua72d24.elisa.omakaista.fi
jcole@abel.spaceapes.com
jcole@main.burghcom.com
jcole@mugatu.jcole.us
jcole@mugatu.spaceapes.com
jcole@sarvik.tfr.cafe.ee
jcole@tetra.spaceapes.com
......
......@@ -185,6 +185,12 @@ struct st_mysql_options {
char *client_ip;
/* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */
my_bool secure_auth;
/* function pointers for local infile support */
int (*local_infile_init)(void **, char *);
int (*local_infile_read)(void *, char *, uint);
int (*local_infile_end)(void *);
int (*local_infile_error)(void *, char *, uint);
};
enum mysql_status
......@@ -384,6 +390,21 @@ my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
unsigned long length);
/* local infile support */
#define LOCAL_INFILE_ERROR_LEN 512
int
mysql_set_local_infile_handler(MYSQL *mysql,
int (*local_infile_init)(void **, char *),
int (*local_infile_read)(void *, char *, uint),
int (*local_infile_end)(void *),
int (*local_infile_error)(void *, char *, uint));
void
mysql_set_local_infile_default(MYSQL *mysql);
/*
enable/disable parsing of all queries to decide if they go on master or
slave
......
......@@ -23,7 +23,7 @@ extern my_string mysql_unix_port;
sig_handler pipe_sig_handler(int sig __attribute__((unused)));
void read_user_name(char *name);
my_bool send_file_to_server(MYSQL *mysql, const char *filename);
my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
/*
Let the user specify that we don't want SIGPIPE; This doesn't however work
......
......@@ -794,35 +794,55 @@ void read_user_name(char *name)
#endif
my_bool send_file_to_server(MYSQL *mysql, const char *filename)
my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
{
int fd, readcount;
my_bool result= 1;
uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
char *buf, tmp_name[FN_REFLEN];
NET *net= &mysql->net;
DBUG_ENTER("send_file_to_server");
int error;
int readcount;
void *li_ptr; /* pass state to local_infile functions */
char *buf = NULL; /* buffer to be filled by local_infile_read */
char *filename = NULL; /* local copy of filename arg */
if (!(buf=my_malloc(packet_length,MYF(0))))
DBUG_ENTER("handle_local_infile");
/* check that we've got valid callback functions */
if (!((mysql->options.local_infile_init) &&
(mysql->options.local_infile_read) &&
(mysql->options.local_infile_end) &&
(mysql->options.local_infile_error)))
{
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(1);
/* if any of the functions is invalid, set the default */
mysql_set_local_infile_default(mysql);
}
fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
/* copy filename into local memory and allocate read buffer */
if ((!(filename = my_strdup(net_filename, MYF(0)))) ||
(!(buf=my_malloc(packet_length, MYF(0)))))
goto oom;
/* initialize local infile (open file, usually) */
if ( (error = (*mysql->options.local_infile_init)(&li_ptr, filename)) )
{
my_net_write(net,"",0); /* Server needs one packet */
net_flush(net);
if(error < 0)
goto oom;
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=EE_FILENOTFOUND;
my_snprintf(net->last_error,sizeof(net->last_error)-1,
EE(net->last_errno),tmp_name, errno);
net->last_errno=error;
(*mysql->options.local_infile_error)(li_ptr,
net->last_error,
sizeof(net->last_error)-1);
goto err;
}
while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
/* read blocks of data from local infile callback */
while ( (readcount =
(*mysql->options.local_infile_read)(li_ptr,
buf,
packet_length) ) > 0)
{
if (my_net_write(net,buf,readcount))
{
......@@ -833,6 +853,7 @@ my_bool send_file_to_server(MYSQL *mysql, const char *filename)
goto err;
}
}
/* Send empty packet to mark end of file */
if (my_net_write(net,"",0) || net_flush(net))
{
......@@ -841,21 +862,136 @@ my_bool send_file_to_server(MYSQL *mysql, const char *filename)
sprintf(net->last_error,ER(net->last_errno),errno);
goto err;
}
if (readcount < 0)
{
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno=EE_READ; /* the errmsg for not entire file read */
my_snprintf(net->last_error,sizeof(net->last_error)-1,
tmp_name,errno);
filename, errno);
goto err;
}
result=0; /* Ok */
err:
if (fd >= 0)
(void) my_close(fd,MYF(0));
my_free(buf,MYF(0));
/* free up memory allocated with _init, usually */
(*mysql->options.local_infile_end)(li_ptr);
my_free(filename, MYF(0));
my_free(buf, MYF(0));
DBUG_RETURN(result);
oom:
/* out of memory */
my_free(filename, MYF(MY_ALLOW_ZERO_PTR));
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
strmov(net->sqlstate, unknown_sqlstate);
strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(1);
}
typedef struct default_local_infile_st {
int fd;
int error_num;
char error_msg[LOCAL_INFILE_ERROR_LEN];
} default_local_infile_data;
int
default_local_infile_init(void **ptr, char *filename)
{
default_local_infile_data *data;
if (!(*ptr= data= ((default_local_infile_data *)
my_malloc(sizeof(default_local_infile_data), MYF(0)))))
return -1; /* out of memory */
*ptr = data; /* save the struct, we need it to return an error */
data->error_msg[0]= 0;
data->error_num= 0;
if ((data->fd = my_open(filename, O_RDONLY, MYF(0))) < 0)
{
my_snprintf(data->error_msg, sizeof(data->error_msg)-1,
EE(EE_FILENOTFOUND), filename, errno);
return data->error_num=errno; /* error */
}
return 0; /* ok */
}
int
default_local_infile_read(void *ptr, char *buf, uint buf_len)
{
default_local_infile_data *data = (default_local_infile_data *) ptr;
return ((int) my_read(data->fd, (byte *)buf, buf_len, MYF(0)));
}
int
default_local_infile_end(void *ptr)
{
default_local_infile_data *data = (default_local_infile_data *) ptr;
if(data)
{
my_close(data->fd, MYF(0));
my_free(ptr, MYF(0));
}
return 0;
}
int
default_local_infile_error(void *ptr, char *error_msg, uint error_msg_len)
{
default_local_infile_data *data = (default_local_infile_data *) ptr;
if(data) {
strmake(error_msg, data->error_msg, error_msg_len);
return data->error_num;
}
else
{
strmake(error_msg, "Internal error", error_msg_len);
return 0;
}
}
int
mysql_set_local_infile_handler(MYSQL *mysql,
int (*local_infile_init)(void **, char *),
int (*local_infile_read)(void *, char *, uint),
int (*local_infile_end)(void *),
int (*local_infile_error)(void *, char *, uint))
{
if(mysql &&
local_infile_init &&
local_infile_read &&
local_infile_end &&
local_infile_error) {
mysql->options.local_infile_init= local_infile_init;
mysql->options.local_infile_read= local_infile_read;
mysql->options.local_infile_end= local_infile_end;
mysql->options.local_infile_error= local_infile_error;
return 0;
}
return 1;
}
void
mysql_set_local_infile_default(MYSQL *mysql)
{
mysql->options.local_infile_init= default_local_infile_init;
mysql->options.local_infile_read= default_local_infile_read;
mysql->options.local_infile_end= default_local_infile_end;
mysql->options.local_infile_error= default_local_infile_error;
}
......
......@@ -1358,12 +1358,15 @@ mysql_init(MYSQL *mysql)
Only enable LOAD DATA INFILE by default if configured with
--enable-local-infile
*/
#if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
#endif
#ifdef HAVE_SMEM
mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name;
#endif
mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
return mysql;
}
......@@ -2282,7 +2285,7 @@ static my_bool cli_read_query_result(MYSQL *mysql)
#ifdef MYSQL_CLIENT
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
int error=send_file_to_server(mysql,(char*) pos);
int error=handle_local_infile(mysql,(char*) pos);
if ((length=net_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(1);
goto get_info; /* Get info packet */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment