summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_loaddata.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mysqlnd/mysqlnd_loaddata.c')
-rw-r--r--ext/mysqlnd/mysqlnd_loaddata.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/ext/mysqlnd/mysqlnd_loaddata.c b/ext/mysqlnd/mysqlnd_loaddata.c
new file mode 100644
index 000000000..f37aff51b
--- /dev/null
+++ b/ext/mysqlnd/mysqlnd_loaddata.c
@@ -0,0 +1,263 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2009 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Georg Richter <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "php.h"
+#include "php_globals.h"
+#include "mysqlnd.h"
+#include "mysqlnd_wireprotocol.h"
+#include "mysqlnd_priv.h"
+#include "mysqlnd_debug.h"
+
+enum_func_status mysqlnd_simple_command_handle_response(MYSQLND *conn,
+ enum php_mysql_packet_type ok_packet,
+ zend_bool silent, enum php_mysqlnd_server_command command,
+ zend_bool ignore_upsert_status
+ TSRMLS_DC);
+
+
+#define ALLOC_CALLBACK_ARGS(a, b, c)\
+if (c) {\
+ a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
+ for (i = b; i < c; i++) {\
+ a[i] = mnd_emalloc(sizeof(zval *));\
+ MAKE_STD_ZVAL(*a[i]);\
+ }\
+}
+
+#define FREE_CALLBACK_ARGS(a, b, c)\
+if (a) {\
+ for (i=b; i < c; i++) {\
+ zval_ptr_dtor(a[i]);\
+ mnd_efree(a[i]);\
+ }\
+ mnd_efree(a);\
+}
+
+/* {{{ mysqlnd_local_infile_init */
+static
+int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS_DC)
+{
+ MYSQLND_INFILE_INFO *info;
+ php_stream_context *context = NULL;
+
+ DBG_ENTER("mysqlnd_local_infile_init");
+
+ *ptr = info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
+
+ /* check open_basedir */
+ if (PG(open_basedir)) {
+ if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
+ strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
+ info->error_no = CR_UNKNOWN_ERROR;
+ DBG_RETURN(1);
+ }
+ }
+
+ info->filename = filename;
+ info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
+
+ if (info->fd == NULL) {
+ snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
+ info->error_no = MYSQLND_EE_FILENOTFOUND;
+ DBG_RETURN(1);
+ }
+
+ DBG_RETURN(0);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_local_infile_read */
+static
+int mysqlnd_local_infile_read(void *ptr, char *buf, unsigned int buf_len TSRMLS_DC)
+{
+ MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
+ int count;
+
+ DBG_ENTER("mysqlnd_local_infile_read");
+
+ count = (int)php_stream_read(info->fd, buf, buf_len);
+
+ if (count < 0) {
+ strcpy(info->error_msg, "Error reading file");
+ info->error_no = CR_UNKNOWN_ERROR;
+ }
+
+ DBG_RETURN(count);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_local_infile_error */
+static
+int mysqlnd_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len TSRMLS_DC)
+{
+ MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
+
+ DBG_ENTER("mysqlnd_local_infile_error");
+
+ if (info) {
+ strlcpy(error_buf, info->error_msg, error_buf_len);
+ DBG_INF_FMT("have info, %d", info->error_no);
+ DBG_RETURN(info->error_no);
+ }
+
+ strlcpy(error_buf, "Unknown error", error_buf_len);
+ DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
+ DBG_RETURN(CR_UNKNOWN_ERROR);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_local_infile_end */
+static
+void mysqlnd_local_infile_end(void *ptr TSRMLS_DC)
+{
+ MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
+
+ if (info) {
+ /* php_stream_close segfaults on NULL */
+ if (info->fd) {
+ php_stream_close(info->fd);
+ info->fd = NULL;
+ }
+ mnd_efree(info);
+ }
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_local_infile_default */
+PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn)
+{
+ conn->infile.local_infile_init = mysqlnd_local_infile_init;
+ conn->infile.local_infile_read = mysqlnd_local_infile_read;
+ conn->infile.local_infile_error = mysqlnd_local_infile_error;
+ conn->infile.local_infile_end = mysqlnd_local_infile_end;
+}
+/* }}} */
+
+/* {{{ mysqlnd_set_local_infile_handler */
+PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname)
+{
+ if (!conn->infile.callback) {
+ MAKE_STD_ZVAL(conn->infile.callback);
+ } else {
+ zval_dtor(conn->infile.callback);
+ }
+ ZVAL_STRING(conn->infile.callback, (char*) funcname, 1);
+}
+/* }}} */
+
+
+static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of local file";
+
+
+/* {{{ mysqlnd_handle_local_infile */
+enum_func_status
+mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC)
+{
+ char *buf;
+ char empty_packet[MYSQLND_HEADER_SIZE];
+ enum_func_status result = FAIL;
+ unsigned int buflen = 4096;
+ void *info = NULL;
+ int bufsize;
+ size_t ret;
+ MYSQLND_INFILE infile;
+
+ DBG_ENTER("mysqlnd_handle_local_infile");
+
+ if (!(conn->options.flags & CLIENT_LOCAL_FILES)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
+ /* write empty packet to server */
+ ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
+ *is_warning = TRUE;
+ goto infile_error;
+ }
+
+ infile = conn->infile;
+ /* allocate buffer for reading data */
+ buf = (char *)mnd_ecalloc(1, buflen);
+
+ *is_warning = FALSE;
+
+ /* init handler: allocate read buffer and open file */
+ if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
+ *is_warning = TRUE;
+ /* error occured */
+ strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
+ conn->error_info.error_no =
+ infile.local_infile_error(info, conn->error_info.error,
+ sizeof(conn->error_info.error) TSRMLS_CC);
+ /* write empty packet to server */
+ ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
+ goto infile_error;
+ }
+
+ /* read data */
+ while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE,
+ buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
+ if ((ret = mysqlnd_stream_write_w_header(conn, buf, bufsize TSRMLS_CC)) < 0) {
+ DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
+ goto infile_error;
+ }
+ }
+
+ /* send empty packet for eof */
+ if ((ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC)) < 0) {
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
+ goto infile_error;
+ }
+
+ /* error during read occured */
+ if (bufsize < 0) {
+ *is_warning = TRUE;
+ DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
+ strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
+ conn->error_info.error_no = infile.local_infile_error(info, conn->error_info.error,
+ sizeof(conn->error_info.error) TSRMLS_CC);
+ goto infile_error;
+ }
+
+ result = PASS;
+
+infile_error:
+ /* get response from server and update upsert values */
+ if (FAIL == mysqlnd_simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY, FALSE TSRMLS_CC)) {
+ result = FAIL;
+ }
+
+ (*conn->infile.local_infile_end)(info TSRMLS_CC);
+ mnd_efree(buf);
+ DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
+ DBG_RETURN(result);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */