1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

Fix for CONC-44: LOAD DATA INFILE can't open utf16le encoded filenames

This commit is contained in:
holzboote@googlemail.com
2013-08-20 16:40:03 +02:00
parent bb809b33fc
commit a6fd66698f
8 changed files with 150 additions and 339 deletions

View File

@@ -22,38 +22,46 @@ extern "C" {
#endif
#define GLOB 0 /* Error maps */
#define GLOBERRS 27 /* Max number of error messages in map's */
#define EE(X) globerrs[ X ] /* Defines to add error to right map */
#define GLOBERRS EE_LASTERROR - EE_FIRSTERROR + 1 /* Max number of error messages in map's */
#define EE(X) globerrs[ (X) - EE_FIRSTERROR ] /* Defines to add error to right map */
extern const char * NEAR globerrs[]; /* my_error_messages is here */
/* Error message numbers in global map */
#define EE_FILENOTFOUND 0
#define EE_CANTCREATEFILE 1
#define EE_READ 2
#define EE_WRITE 3
#define EE_BADCLOSE 4
#define EE_OUTOFMEMORY 5
#define EE_DELETE 6
#define EE_LINK 7
#define EE_EOFERR 9
#define EE_CANTLOCK 10
#define EE_CANTUNLOCK 11
#define EE_DIR 12
#define EE_STAT 13
#define EE_CANT_CHSIZE 14
#define EE_CANT_OPEN_STREAM 15
#define EE_GETWD 16
#define EE_SETWD 17
#define EE_LINK_WARNING 18
#define EE_OPEN_WARNING 19
#define EE_DISK_FULL 20
#define EE_CANT_MKDIR 21
#define EE_UNKNOWN_CHARSET 22
/* Error message numbers in global map
*/
#define EE_FIRSTERROR 1
#define EE_CANTCREATEFILE 1
#define EE_READ 2
#define EE_WRITE 3
#define EE_BADCLOSE 4
#define EE_OUTOFMEMORY 5
#define EE_DELETE 6
#define EE_LINK 7
#define EE_EOFERR 9
#define EE_CANTLOCK 10
#define EE_CANTUNLOCK 11
#define EE_DIR 12
#define EE_STAT 13
#define EE_CANT_CHSIZE 14
#define EE_CANT_OPEN_STREAM 15
#define EE_GETWD 16
#define EE_SETWD 17
#define EE_LINK_WARNING 18
#define EE_OPEN_WARNING 19
#define EE_DISK_FULL 20
#define EE_CANT_MKDIR 21
#define EE_UNKNOWN_CHARSET 22
#define EE_OUT_OF_FILERESOURCES 23
#define EE_CANT_READLINK 24
#define EE_CANT_SYMLINK 25
#define EE_REALPATH 26
#define EE_CANT_READLINK 24
#define EE_CANT_SYMLINK 25
#define EE_REALPATH 26
#define EE_SYNC 27
#define EE_UNKNOWN_COLLATION 28
#define EE_FILENOTFOUND 29
#define EE_FILE_NOT_CLOSED 30
#define EE_CANT_CHMOD 31
#define EE_LASTERROR 31
#ifdef __cplusplus
}

View File

@@ -44,14 +44,11 @@ mf_format.c
mf_loadpath.c
mf_pack.c
mf_path.c
mf_tempfile.c
mf_unixpath.c
mf_wcomp.c
mulalloc.c
my_alloc.c
my_compress.c
my_create.c
my_delete.c
my_div.c
my_error.c
my_fopen.c

View File

@@ -22,7 +22,6 @@
const char * NEAR globerrs[GLOBERRS]=
{
"File '%s' not found (Errcode: %d)",
"Can't create/write to file '%s' (Errcode: %d)",
"Error reading file '%s' (Errcode: %d)",
"Error writing file '%s' (Errcode: %d)",
@@ -41,14 +40,19 @@ const char * NEAR globerrs[GLOBERRS]=
"Can't get working dirctory (Errcode: %d)",
"Can't change dir to '%s' (Errcode: %d)",
"Warning: '%s' had %d links",
"%d files and %d streams is left open\n",
"Disk is full writing '%s'. Waiting for someone to free space...",
"Warning: %d files and %d streams is left open\n",
"Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... (Expect up to %d secs delay for server to continue after freeing disk space)",
"Can't create directory '%s' (Errcode: %d)",
"Character set '%s' is not a compiled character set and is not specified in the '%s' file",
"Out of resources when opening file '%s' (Errcode: %d)",
"Can't read value for symlink '%s' (Error %d)",
"Can't create symlink '%s' pointing at '%s' (Error %d)",
"Error on realpath() on '%s' (Error %d)",
"Can't sync file '%s' to disk (Errcode: %d)",
"Collation '%s' is not a compiled collation and is not specified in the '%s' file",
"File '%s' not found (Errcode: %d)",
"File '%s' (fileno: %d) was not closed",
"Can't change mode for file '%s' to 0x%lx (Error: %d)"
};
void init_glob_errs(void)

View File

@@ -1,198 +0,0 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA */
#include "mysys_priv.h"
#include <m_string.h>
#include "my_static.h"
#include "mysys_err.h"
#include <errno.h>
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_TEMPNAM
#if !defined( MSDOS) && !defined(OS2)
extern char **environ;
#endif
#endif
/*
Create a temporary file in a given directory
This function should be used instead of my_tempnam() !
*/
File create_temp_file(char *to, const char *dir, const char *prefix,
int mode __attribute__((unused)),
myf MyFlags __attribute__((unused)))
{
File file= -1;
DBUG_ENTER("create_temp_file");
#if defined(_MSC_VER)
{
char temp[FN_REFLEN],*end,*res,**old_env,*temp_env[1];
old_env=environ;
if (dir)
{
end=strend(dir)-1;
if (!dir[0])
{ /* Change empty string to current dir */
to[0]= FN_CURLIB;
to[1]= 0;
dir=to;
}
else if (*end == FN_DEVCHAR)
{ /* Get current dir for drive */
_fullpath(temp,dir,FN_REFLEN);
dir=to;
}
else if (*end == FN_LIBCHAR && dir < end && end[-1] != FN_DEVCHAR)
{
strmake(to,dir,(uint) (end-dir)); /* Copy and remove last '\' */
dir=to;
}
environ=temp_env; /* Force use of dir (dir not checked) */
temp_env[0]=0;
}
if ((res=tempnam((char*) dir,(char *) prefix)))
{
strmake(to,res,FN_REFLEN-1);
(*free)(res);
file=my_create(to,0, mode, MyFlags);
}
environ=old_env;
}
#elif defined(_ZTC__)
if (!dir)
dir=getenv("TMPDIR");
if ((res=tempnam((char*) dir,(char *) prefix)))
{
strmake(to,res,FN_REFLEN-1);
(*free)(res);
file=my_create(to, 0, mode, MyFlags);
}
#elif defined(HAVE_MKSTEMP)
{
char prefix_buff[30];
uint pfx_len;
File org_file;
pfx_len=(strmov(strnmov(prefix_buff,
prefix ? prefix : "tmp.",
sizeof(prefix_buff)-7),"XXXXXX") - prefix_buff);
if (!dir && ! (dir =getenv("TMPDIR")))
dir=P_tmpdir;
if (strlen(dir)+ pfx_len > FN_REFLEN-2)
{
errno=my_errno= ENAMETOOLONG;
return 1;
}
strmov(to,dir);
strmov(convert_dirname(to),prefix_buff);
org_file=mkstemp(to);
file=my_register_filename(org_file, to, FILE_BY_MKSTEMP,
EE_CANTCREATEFILE, MyFlags);
/* If we didn't manage to register the name, remove the temp file */
if (org_file >= 0 && file < 0)
{
int tmp=my_errno;
(void) my_delete(to, MYF(MY_WME | ME_NOINPUT));
my_errno=tmp;
}
}
#elif defined(HAVE_TEMPNAM)
{
char *res,**old_env,*temp_env[1];
if (dir && !dir[0])
{ /* Change empty string to current dir */
to[0]= FN_CURLIB;
to[1]= 0;
dir=to;
}
#ifdef OS2
// changing environ variable doesn't work with VACPP
char buffer[256];
sprintf( buffer, "TMP=%s", dir);
// remove ending backslash
if (buffer[strlen(buffer)-1] == '\\')
buffer[strlen(buffer)-1] = '\0';
putenv( buffer);
#else
old_env= (char**) environ;
if (dir)
{ /* Don't use TMPDIR if dir is given */
environ=(const char**) temp_env;
temp_env[0]=0;
}
#endif
if ((res=tempnam((char*) dir, (char*) prefix)))
{
strmake(to,res,FN_REFLEN-1);
(*free)(res);
file=my_create(to,0,
(int) (O_RDWR | O_BINARY | O_TRUNC |
O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME));
}
else
{
DBUG_PRINT("error",("Got error: %d from tempnam",errno));
}
#ifndef OS2
environ=(const char**) old_env;
#endif
}
#else
{
register long uniq;
register int length;
my_string pos,end_pos;
/* Make an unique number */
pthread_mutex_lock(&THR_LOCK_open);
uniq= ((long) getpid() << 20) + (long) _my_tempnam_used++ ;
pthread_mutex_unlock(&THR_LOCK_open);
if (!dir && !(dir=getenv("TMPDIR"))) /* Use this if possibly */
dir=P_tmpdir; /* Use system default */
length=strlen(dir)+strlen(pfx)+1;
DBUG_PRINT("test",("mallocing %d byte",length+8+sizeof(TMP_EXT)+1));
if (length+8+sizeof(TMP_EXT)+1 > FN_REFLENGTH)
errno=my_errno= ENAMETOOLONG;
else
{
end_pos=strmov(to,dir);
if (end_pos != to && end_pos[-1] != FN_LIBCHAR)
*end_pos++=FN_LIBCHAR;
end_pos=strmov(end_pos,pfx);
for (length=0 ; length < 8 && uniq ; length++)
{
*end_pos++= _dig_vec[(int) (uniq & 31)];
uniq >>= 5;
}
(void) strmov(end_pos,TMP_EXT);
file=my_create(to,0,
(int) (O_RDWR | O_BINARY | O_TRUNC |
O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME));
}
}
#endif
if (file >= 0)
thread_safe_increment(my_tmp_file_created,&THR_LOCK_open);
DBUG_RETURN(file);
}

View File

@@ -1,64 +0,0 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA */
#define USES_TYPES
#include "mysys_priv.h"
#include <my_dir.h>
#include "mysys_err.h"
#include <errno.h>
#if defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
#include <share.h>
#endif
/*
** Create a new file
** Arguments:
** Path-name of file
** Read | write on file (umask value)
** Read & Write on open file
** Special flags
*/
File my_create(const char *FileName, int CreateFlags, int access_flags,
myf MyFlags)
{
int fd;
DBUG_ENTER("my_create");
DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
FileName, CreateFlags, access_flags, MyFlags));
#if !defined(NO_OPEN_3) && !defined(__EMX__)
fd = open((my_string) FileName, access_flags | O_CREAT,
CreateFlags ? CreateFlags : my_umask);
#elif defined(VMS)
fd = open((my_string) FileName, access_flags | O_CREAT, 0,
"ctx=stm","ctx=bin");
#elif defined(MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(OS2)
if (access_flags & O_SHARE)
fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
else
fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
MY_S_IREAD | MY_S_IWRITE);
#else
fd = open(FileName, access_flags);
#endif
DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_CREATE,
EE_CANTCREATEFILE, MyFlags));
} /* my_create */

View File

@@ -1,36 +0,0 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA */
#include "mysys_priv.h"
#include "mysys_err.h"
int my_delete(const char *name, myf MyFlags)
{
int err;
DBUG_ENTER("my_delete");
DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
if ((err = unlink(name)) == -1)
{
my_errno=errno;
if (MyFlags & (MY_FAE+MY_WME))
my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
name,errno);
}
DBUG_RETURN(err);
} /* my_delete */

View File

@@ -47,6 +47,9 @@
#include "errmsg.h"
#include "mysql.h"
#include <string.h>
#ifdef _WIN32
#include <share.h>
#endif
typedef struct st_mysql_infile_info
{
@@ -61,7 +64,12 @@ static
int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
{
MYSQL_INFILE_INFO *info;
int CodePage= -1;
#ifdef _WIN32
MYSQL *mysql= (MYSQL *)userdata;
wchar_t *w_filename= NULL;
int Length;
#endif
DBUG_ENTER("mysql_local_infile_init");
info = (MYSQL_INFILE_INFO *)my_malloc(sizeof(MYSQL_INFILE_INFO), MYF(MY_ZEROFILL));
@@ -72,7 +80,47 @@ int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
*ptr = info;
info->filename = filename;
info->fd = my_open(info->filename, O_RDONLY, MYF(0));
#ifdef _WIN32
if (mysql)
CodePage= madb_get_windows_cp(mysql->charset->csname);
#endif
if (CodePage == -1)
{
#ifdef _WIN32
info->fd= sopen(info->filename, _O_RDONLY, _SH_DENYNO , _S_IREAD | _S_IWRITE);
#else
info->fd = open(info->filename, O_RDONLY | O_BINARY, my_umask);
#endif
my_errno= errno;
}
#ifdef _WIN32
else
{
if ((Length= MultiByteToWideChar(CodePage, 0, info->filename, strlen(info->filename), NULL, 0)))
{
if (!(w_filename= (wchar_t *)my_malloc((Length + 1) * sizeof(wchar_t), MYF(MY_ZEROFILL))))
{
info->error_no= CR_OUT_OF_MEMORY;
my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
ER(CR_OUT_OF_MEMORY));
DBUG_RETURN(1);
}
Length= MultiByteToWideChar(CodePage, 0, info->filename, strlen(info->filename), w_filename, Length);
}
if (Length == 0)
{
my_free((gptr)w_filename, MYF(0));
info->error_no= CR_UNKNOWN_ERROR;
my_snprintf((char *)info->error_msg, sizeof(info->error_msg),
"Character conversion error: %d", GetLastError());
DBUG_RETURN(1);
}
info->fd= _wsopen(w_filename, _O_RDONLY, _SH_DENYNO , _S_IREAD | _S_IWRITE);
my_errno= errno;
my_free((gptr)w_filename, MYF(0));
}
#endif
if (info->fd < 0)
{
@@ -95,7 +143,7 @@ int mysql_local_infile_read(void *ptr, char * buf, unsigned int buf_len)
DBUG_ENTER("mysql_local_infile_read");
count= my_read(info->fd, buf, buf_len, MYF(0));
count= read(info->fd, (void *)buf, (size_t)buf_len);
if (count < 0)
{
@@ -137,8 +185,8 @@ void mysql_local_infile_end(void *ptr)
if (info)
{
if (info->fd >= 0)
my_close(info->fd, MYF(0));
my_free(ptr, MYF(0));
close(info->fd);
my_free((gptr)ptr, MYF(0));
}
DBUG_VOID_RETURN;
}
@@ -197,8 +245,10 @@ my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename)
/* check if all callback functions exist */
if (!conn->options.local_infile_init || !conn->options.local_infile_end ||
!conn->options.local_infile_read || !conn->options.local_infile_error)
{
conn->options.local_infile_userdata= conn;
mysql_set_local_infile_default(conn);
}
/* allocate buffer for reading data */
buf = (uchar *)my_malloc(buflen, MYF(0));
@@ -250,3 +300,4 @@ infile_error:
DBUG_RETURN(result);
}
/* }}} */

View File

@@ -799,7 +799,7 @@ static int test_bug49694(MYSQL *mysql)
fprintf (fp, "%.08d,%d,%f\r\n", 100 + i, i % 3 + 1, 60000.0 + i/100);
fclose(fp);
rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE './data.csv' INTO TABLE enclist "
rc= mysql_query(mysql, "LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE enclist "
"FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'");
check_mysql_rc(rc, mysql);
@@ -838,6 +838,52 @@ static int test_ldi_path(MYSQL *mysql)
return OK;
}
#if _WIN32
static int test_conc44(MYSQL *mysql)
{
char query[1024];
char *a_filename= "æøå.csv";
int rc;
int i;
FILE *fp;
rc= mysql_set_character_set(mysql, "latin1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS enclist");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE `enclist` ("
" `pat_id` int(11) NOT NULL,"
" `episode_id` int(11) NOT NULL,"
" `enc_id` double NOT NULL,"
" PRIMARY KEY (`pat_id`,`episode_id`,`enc_id`)"
") ENGINE=MyISAM DEFAULT CHARSET=latin1");
check_mysql_rc(rc, mysql);
fp= fopen(a_filename, "w");
FAIL_IF(!fp, "Can't open file");
for (i=0; i < 100; i++)
fprintf (fp, "%.08d,%d,%f\r\n", 100 + i, i % 3 + 1, 60000.0 + i/100);
fclose(fp);
sprintf(query, "LOAD DATA LOCAL INFILE '%s' INTO TABLE enclist "
"FIELDS TERMINATED BY '.' LINES TERMINATED BY '\r\n'", a_filename);
rc= mysql_query(mysql, query);
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "DELETE FROM enclist");
check_mysql_rc(rc, mysql);
FAIL_IF(mysql_affected_rows(mysql) != 100, "Import failure. Expected 2 imported rows");
rc= mysql_query(mysql, "DROP TABLE enclist");
check_mysql_rc(rc, mysql);
return OK;
}
#endif
struct my_tests_st my_tests[] = {
{"test_bug28075", test_bug28075, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_bug28505", test_bug28505, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
@@ -853,6 +899,9 @@ struct my_tests_st my_tests[] = {
{"test_wl4284_1", test_wl4284_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_bug49694", test_bug49694, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"test_ldi_path", test_ldi_path, TEST_CONNECTION_NEW, 0, NULL, NULL},
#ifdef _WIN32
{"test_conc44", test_conc44, TEST_CONNECTION_NEW, 0, NULL, NULL},
#endif
{NULL, NULL, 0, 0, NULL, 0}
};