12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
17
/* Copy data from a textfile to table */
19
19
#include "config.h"
20
21
#include <drizzled/sql_load.h>
21
22
#include <drizzled/error.h>
22
23
#include <drizzled/data_home.h>
23
24
#include <drizzled/session.h>
24
25
#include <drizzled/sql_base.h>
25
#include <drizzled/field/timestamp.h>
26
#include <drizzled/field/epoch.h>
26
27
#include "drizzled/internal/my_sys.h"
27
28
#include "drizzled/internal/iocache.h"
28
29
#include <drizzled/db.h>
30
#include "drizzled/plugin/storage_engine.h"
30
32
#include <sys/stat.h>
32
34
#include <algorithm>
36
#include <boost/filesystem.hpp>
38
namespace fs=boost::filesystem;
35
39
using namespace std;
74
78
void end_io_cache()
76
internal::end_io_cache(&cache);
77
81
need_end_io_cache = 0;
81
85
Either this method, or we need to make cache public
82
Arg must be set from mysql_load() since constructor does not see
86
Arg must be set from load() since constructor does not see
83
87
either the table or Session value
85
89
void set_io_cache_arg(void* arg) { cache.arg = arg; }
88
static int read_fixed_length(Session *session, COPY_INFO &info, TableList *table_list,
92
static int read_fixed_length(Session *session, CopyInfo &info, TableList *table_list,
89
93
List<Item> &fields_vars, List<Item> &set_fields,
90
94
List<Item> &set_values, READ_INFO &read_info,
91
95
uint32_t skip_lines,
92
96
bool ignore_check_option_errors);
93
static int read_sep_field(Session *session, COPY_INFO &info, TableList *table_list,
97
static int read_sep_field(Session *session, CopyInfo &info, TableList *table_list,
94
98
List<Item> &fields_vars, List<Item> &set_fields,
95
99
List<Item> &set_values, READ_INFO &read_info,
96
100
String &enclosed, uint32_t skip_lines,
117
121
true - error / false - success
120
int mysql_load(Session *session,file_exchange *ex,TableList *table_list,
124
int load(Session *session,file_exchange *ex,TableList *table_list,
121
125
List<Item> &fields_vars, List<Item> &set_fields,
122
126
List<Item> &set_values,
123
127
enum enum_duplicates handle_duplicates, bool ignore)
125
char name[FN_REFLEN];
127
130
Table *table= NULL;
129
132
String *field_term=ex->field_term,*escaped=ex->escaped;
130
133
String *enclosed=ex->enclosed;
132
char *db= table_list->db; // This is never null
136
assert(table_list->getSchemaName()); // This should never be null
135
139
If path for cursor is not defined, we will use the current database.
136
140
If this is not set, we will use the directory where the table to be
137
141
loaded is located
139
const char *tdb= session->db.empty() ? db : session->db.c_str(); // Result is never null
143
util::string::const_shared_ptr schema(session->schema());
144
const char *tdb= (schema and not schema->empty()) ? schema->c_str() : table_list->getSchemaName(); // Result should never be null
141
146
uint32_t skip_lines= ex->skip_lines;
142
147
bool transactional_table;
143
Session::killed_state killed_status= Session::NOT_KILLED;
148
Session::killed_state_t killed_status= Session::NOT_KILLED;
145
150
/* Escape and enclosed character may be a utf8 4-byte character */
146
151
if (escaped->length() > 4 || enclosed->length() > 4)
256
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
257
ex->file_name+=dirname_length(ex->file_name);
259
if (!internal::dirname_length(ex->file_name))
261
strcpy(name, drizzle_real_data_home);
262
strncat(name, tdb, FN_REFLEN-strlen(drizzle_real_data_home)-1);
263
(void) internal::fn_format(name, ex->file_name, name, "",
264
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
268
(void) internal::fn_format(name, ex->file_name, drizzle_real_data_home, "",
269
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
271
if (opt_secure_file_priv &&
272
strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
274
/* Read only allowed from within dir specified by secure_file_priv */
275
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
279
struct stat stat_info;
280
if (stat(name,&stat_info))
282
my_error(ER_FILE_NOT_FOUND, MYF(0), name, errno);
286
// if we are not in slave thread, the cursor must be:
287
if (!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
288
(stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
289
((stat_info.st_mode & S_IFREG) == S_IFREG ||
290
(stat_info.st_mode & S_IFIFO) == S_IFIFO)))
292
my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
295
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
298
if ((file=internal::my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
300
my_error(ER_CANT_OPEN_FILE, MYF(0), name, errno);
262
fs::path to_file(ex->file_name);
263
fs::path target_path(fs::system_complete(getDataHomeCatalog()));
264
if (not to_file.has_root_directory())
266
int count_elements= 0;
267
for (fs::path::iterator iter= to_file.begin();
268
iter != to_file.end();
269
++iter, ++count_elements)
272
if (count_elements == 1)
276
target_path /= to_file;
280
target_path= to_file;
283
if (not secure_file_priv.string().empty())
285
if (target_path.file_string().substr(0, secure_file_priv.file_string().size()) != secure_file_priv.file_string())
287
/* Read only allowed from within dir specified by secure_file_priv */
288
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
293
struct stat stat_info;
294
if (stat(target_path.file_string().c_str(), &stat_info))
296
my_error(ER_FILE_NOT_FOUND, MYF(0), target_path.file_string().c_str(), errno);
300
// if we are not in slave thread, the cursor must be:
301
if (!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
302
(stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
303
((stat_info.st_mode & S_IFREG) == S_IFREG ||
304
(stat_info.st_mode & S_IFIFO) == S_IFIFO)))
306
my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), target_path.file_string().c_str());
309
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
313
if ((file=internal::my_open(target_path.file_string().c_str(), O_RDONLY,MYF(MY_WME))) < 0)
315
my_error(ER_CANT_OPEN_FILE, MYF(0), target_path.file_string().c_str(), errno);
306
319
memset(&info, 0, sizeof(info));
307
320
info.ignore= ignore;
308
321
info.handle_duplicates=handle_duplicates;
309
322
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
324
identifier::Schema identifier(*schema);
311
325
READ_INFO read_info(file, tot_length,
312
ex->cs ? ex->cs : get_default_db_collation(session->db.c_str()),
313
*field_term,*ex->line_start, *ex->line_term, *enclosed,
326
ex->cs ? ex->cs : plugin::StorageEngine::getSchemaCollation(identifier),
327
*field_term, *ex->line_start, *ex->line_term, *enclosed,
314
328
info.escape_char, is_fifo);
315
329
if (read_info.error)
376
390
internal::my_close(file,MYF(0));
377
391
free_blobs(table); /* if pack_blob was used */
378
392
table->copy_blobs=0;
379
session->count_cuted_fields= CHECK_FIELD_IGNORE;
393
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
381
395
simulated killing in the middle of per-row loop
382
396
must be effective for binlogging
384
killed_status= (error == 0)? Session::NOT_KILLED : session->killed;
398
killed_status= (error == 0)? Session::NOT_KILLED : session->getKilled();
387
401
error= -1; // Error on read
390
sprintf(name, ER(ER_LOAD_INFO), (uint32_t) info.records, (uint32_t) info.deleted,
391
(uint32_t) (info.records - info.copied), (uint32_t) session->cuted_fields);
406
snprintf(msg, sizeof(msg), ER(ER_LOAD_INFO), info.records, info.deleted,
407
(info.records - info.copied), session->cuted_fields);
393
409
if (session->transaction.stmt.hasModifiedNonTransData())
394
410
session->transaction.all.markModifiedNonTransData();
396
412
/* ok to client sent only after binlog write and engine commit */
397
session->my_ok(info.copied + info.deleted, 0, 0L, name);
413
session->my_ok(info.copied + info.deleted, 0, 0L, msg);
399
415
assert(transactional_table || !(info.copied || info.deleted) ||
400
416
session->transaction.stmt.hasModifiedNonTransData());
401
417
table->cursor->ha_release_auto_increment();
402
418
table->auto_increment_field_not_null= false;
403
session->abort_on_warning= 0;
419
session->setAbortOnWarning(false);