diff options
author | jcole@mugatu.jcole.us <> | 2004-03-22 19:58:49 -0500 |
---|---|---|
committer | jcole@mugatu.jcole.us <> | 2004-03-22 19:58:49 -0500 |
commit | 15cc92cacbaea69efda90bf5d4dae0938d87a933 (patch) | |
tree | 809c07d307c0ec006017f9354e45bf2a1e6443f3 | |
parent | de09e55b8bb7495c8d5cddeed28eb28177a39aa5 (diff) | |
download | mariadb-git-15cc92cacbaea69efda90bf5d4dae0938d87a933.tar.gz |
Added LOCAL INFILE callback function support.
-rw-r--r-- | BitKeeper/etc/logging_ok | 1 | ||||
-rw-r--r-- | include/mysql.h | 21 | ||||
-rw-r--r-- | libmysql/client_settings.h | 2 | ||||
-rw-r--r-- | libmysql/libmysql.c | 172 | ||||
-rw-r--r-- | sql-common/client.c | 5 |
5 files changed, 181 insertions, 20 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index db98622657e..7a75d7a9873 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -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 diff --git a/include/mysql.h b/include/mysql.h index e14381a94de..d922b552e38 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -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 diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index 9fc8e67df27..3fdadf29dea 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -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 diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 0a93fe60990..357c85c09b2 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -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; } diff --git a/sql-common/client.c b/sql-common/client.c index 27492e8d405..b94f3e1de38 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -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 @@ get_info: #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 */ |