summaryrefslogtreecommitdiff
path: root/sql/discover.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/discover.cc')
-rw-r--r--sql/discover.cc178
1 files changed, 160 insertions, 18 deletions
diff --git a/sql/discover.cc b/sql/discover.cc
index b9dba92a780..4224e8ce0b0 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -45,7 +45,7 @@
3 Could not allocate data for read. Could not read file
*/
-int readfrm(const char *name, uchar **frmdata, size_t *len)
+int readfrm(const char *name, const uchar **frmdata, size_t *len)
{
int error;
char index_file[FN_REFLEN];
@@ -70,13 +70,17 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
error= 2;
if (mysql_file_fstat(file, &state, MYF(0)))
goto err;
- read_len= (size_t)state.st_size;
+ read_len= (size_t)min(FRM_MAX_SIZE, state.st_size); // safety
// Read whole frm file
error= 3;
- read_data= 0; // Nothing to free
- if (read_string(file, &read_data, read_len))
+ if (!(read_data= (uchar*)my_malloc(read_len, MYF(MY_WME))))
goto err;
+ if (mysql_file_read(file, read_data, read_len, MYF(MY_NABP)))
+ {
+ my_free(read_data);
+ goto err;
+ }
// Setup return data
*frmdata= (uchar*) read_data;
@@ -96,7 +100,7 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
Write the content of a frm data pointer
to a frm file.
- @param name path to table-file "db/name"
+ @param path path to table-file "db/name"
@param frmdata frm data
@param len length of the frmdata
@@ -106,29 +110,167 @@ int readfrm(const char *name, uchar **frmdata, size_t *len)
2 Could not write file
*/
-int writefrm(const char *name, const uchar *frmdata, size_t len)
+int writefrm(const char *path, const char *db, const char *table,
+ bool tmp_table, const uchar *frmdata, size_t len)
{
- File file;
- char index_file[FN_REFLEN];
+ char file_name[FN_REFLEN+1];
int error;
+ int create_flags= O_RDWR | O_TRUNC;
DBUG_ENTER("writefrm");
- DBUG_PRINT("enter",("name: '%s' len: %lu ",name, (ulong) len));
+ DBUG_PRINT("enter",("name: '%s' len: %lu ",path, (ulong) len));
- error= 0;
- if ((file= mysql_file_create(key_file_frm,
- fn_format(index_file, name, "", reg_ext,
- MY_UNPACK_FILENAME | MY_APPEND_EXT),
- CREATE_MODE, O_RDWR | O_TRUNC,
- MYF(MY_WME))) >= 0)
+ if (tmp_table)
+ create_flags|= O_EXCL | O_NOFOLLOW;
+
+ strxnmov(file_name, sizeof(file_name)-1, path, reg_ext, NullS);
+
+ File file= mysql_file_create(key_file_frm, file_name,
+ CREATE_MODE, create_flags, MYF(0));
+
+ if ((error= file < 0))
{
- if (mysql_file_write(file, frmdata, len, MYF(MY_WME | MY_NABP)))
- error= 2;
- (void) mysql_file_close(file, MYF(0));
+ if (my_errno == ENOENT)
+ my_error(ER_BAD_DB_ERROR, MYF(0), db);
+ else
+ my_error(ER_CANT_CREATE_TABLE, MYF(0), db, table, my_errno);
+ }
+ else
+ {
+ error= mysql_file_write(file, frmdata, len, MYF(MY_WME | MY_NABP));
+
+ if (!error && !tmp_table && opt_sync_frm)
+ error= mysql_file_sync(file, MYF(MY_WME)) ||
+ my_sync_dir_by_file(file_name, MYF(MY_WME));
+
+ error|= mysql_file_close(file, MYF(MY_WME));
}
DBUG_RETURN(error);
} /* writefrm */
+static inline void advance(FILEINFO* &from, FILEINFO* &to,
+ FILEINFO* cur, bool &skip)
+{
+ if (skip) // if not copying
+ from= cur; // just advance the start pointer
+ else // if copying
+ if (to == from) // but to the same place (not shifting the data)
+ from= to= cur; // advance both pointers
+ else // otherwise
+ while (from < cur) // have to copy [from...cur) to [to...)
+ *to++ = *from++;
+ skip= false;
+}
+/**
+ Go through the directory listing looking for files with a specified
+ extension and add them to the result list
+
+ @details
+ This function may be called many times on the same directory listing
+ but with different extensions. To avoid discovering the same table twice,
+ whenever a table file is discovered, all files with the same name
+ (independently from the extensions) are removed from the list.
+ Example: the list contained
+ { "db.opt", "t1.MYD", "t1.MYI", "t1.frm", "t2.ARZ", "t3.ARZ", "t3.frm" }
+ on discovering all ".frm" files, tables "t1" and "t3" will be found,
+ and list will become
+ { "db.opt", "t2.ARZ" }
+ and now ".ARZ" discovery can discover the table "t2"
+ @note
+ This function assumes that the directory listing is sorted alphabetically.
+
+ @note Partitioning makes this more complicated. A partitioned table t1 might
+ have files, like t1.frm, t1#P#part1.ibd, t1#P#foo.ibd, etc.
+ That means we need to compare file names only up to the first '#' or '.'
+ whichever comes first.
+*/
+int extension_based_table_discovery(MY_DIR *dirp, const char *ext_meta,
+ handlerton::discovered_list *result)
+{
+ CHARSET_INFO *cs= character_set_filesystem;
+ size_t ext_meta_len= strlen(ext_meta);
+ FILEINFO *from, *to, *cur, *end;
+ bool skip= false;
+
+ from= to= cur= dirp->dir_entry;
+ end= cur + dirp->number_of_files;
+ while (cur < end)
+ {
+ char *octothorp= strrchr(cur->name, '#');
+ char *ext= strchr(octothorp ? octothorp : cur->name, FN_EXTCHAR);
+
+ if (ext && octothorp != cur->name)
+ {
+ size_t len= (octothorp ? octothorp : ext) - cur->name;
+ if (from != cur &&
+ (my_strnncoll(cs, (uchar*)from->name, len, (uchar*)cur->name, len) ||
+ (from->name[len] != FN_EXTCHAR && from->name[len] != '#')))
+ advance(from, to, cur, skip);
+
+ if (my_strnncoll(cs, (uchar*)ext, strlen(ext),
+ (uchar*)ext_meta, ext_meta_len) == 0)
+ {
+ *ext = 0;
+ if (result->add_file(cur->name))
+ return 1;
+ *ext = FN_EXTCHAR;
+ skip= true; // table discovered, skip all files with the same name
+ }
+ }
+ else
+ {
+ advance(from, to, cur, skip);
+ from++;
+ }
+
+ cur++;
+ }
+ advance(from, to, cur, skip);
+ dirp->number_of_files= to - dirp->dir_entry;
+ return 0;
+}
+
+/**
+ Simple, not reusable file-based table discovery
+
+ @details
+ simplified version of extension_based_table_discovery(), that does not
+ modify the list of files. It cannot be called many times for the same
+ directory listing, otherwise it'll produce duplicate results.
+
+ @note
+ For backward compatibility reasons, this will find tables with names,
+ starting from '#', as long as they don't start from '#sql-'.
+ These names are invalid since 5.0, and the compex discovery function
+ will ignore them. Anyone still having these files, should disable
+ discovering engines, and rename these invalid table files.
+*/
+int ext_table_discovery_simple(MY_DIR *dirp,
+ handlerton::discovered_list *result)
+{
+ CHARSET_INFO *cs= character_set_filesystem;
+ FILEINFO *cur, *end;
+
+ cur= dirp->dir_entry;
+ end= cur + dirp->number_of_files;
+ while (cur < end)
+ {
+ char *ext= strrchr(cur->name, FN_EXTCHAR);
+
+ if (ext && !is_prefix(cur->name, tmp_file_prefix))
+ {
+ if (my_strnncoll(cs, (uchar*)ext, strlen(ext),
+ (uchar*)reg_ext, reg_ext_length) == 0)
+ {
+ *ext = 0;
+ if (result->add_file(cur->name))
+ return 1;
+ }
+ }
+ cur++;
+ }
+ return 0;
+}