wildcard matching
This commit is contained in:
		| @ -25,6 +25,10 @@ | ||||
| #include "sql/resolver/dml/ob_delete_resolver.h" | ||||
| #include "lib/json/ob_json.h" | ||||
| #include "lib/json/ob_json_print_utils.h" | ||||
| #include "share/backup/ob_backup_io_adapter.h" | ||||
| #include "share/backup/ob_backup_struct.h" | ||||
| #include "lib/restore/ob_storage_info.h" | ||||
| #include <glob.h> | ||||
|  | ||||
| namespace oceanbase | ||||
| { | ||||
| @ -503,6 +507,58 @@ int ObLoadDataResolver::resolve_hints(const ParseNode &node) | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObLoadDataResolver::pattern_match(const ObString& str, const ObString& pattern, bool &matched) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   bool *dp = nullptr; | ||||
|   int32_t m = str.length() + 1; | ||||
|   int32_t n = pattern.length() + 1; | ||||
|   ObMemAttr attr(MTL_ID(), "TLD_PATMATCH"); | ||||
|   if (OB_ISNULL(dp = (bool *)ob_malloc(m * n, attr))) { | ||||
|     ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|     LOG_WARN("fail to alloc memory", K(ret)); | ||||
|   } else { | ||||
|     memset(dp, false, m * n); | ||||
|     dp[0] = true; | ||||
|     for (int32_t j = 1; j < n; j++) { | ||||
|       if (pattern[j - 1] == '*') { | ||||
|         dp[j] = dp[j - 1]; | ||||
|       } | ||||
|     } | ||||
|     for (int32_t i = 1; i < m; i++) { | ||||
|       for (int32_t j = 1; j < n; j++) { | ||||
|         if (pattern[j - 1] == '?' || pattern[j - 1] == str[i - 1]) { | ||||
|           dp[i * n + j] = dp[(i - 1) * n + j - 1]; | ||||
|         } else if (pattern[j - 1] == '*') { | ||||
|           dp[i * n + j] = dp[(i - 1) * n + j] || dp[i * n + j - 1]; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     matched = dp[m * n - 1]; | ||||
|   } | ||||
|   if (OB_NOT_NULL(dp)) { | ||||
|     ob_free(dp); | ||||
|     dp = nullptr; | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| bool ObLoadDataResolver::exist_wildcard(const ObString& str) | ||||
| { | ||||
|   bool has_wildcard = false; | ||||
|   ObString wildcards("?*[]"); | ||||
|   for (int32_t i = 0; !has_wildcard && i < str.length(); i++) { | ||||
|     for (int32_t j = 0; !has_wildcard && j < wildcards.length(); j++) { | ||||
|       if (str[i] == wildcards[j]) { | ||||
|         has_wildcard = true; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return has_wildcard; | ||||
| } | ||||
|  | ||||
| int ObLoadDataResolver::resolve_filename(ObLoadDataStmt *load_stmt, ParseNode *node) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
| @ -518,77 +574,167 @@ int ObLoadDataResolver::resolve_filename(ObLoadDataStmt *load_stmt, ParseNode *n | ||||
|     if (OB_UNLIKELY(file_name.empty())) { | ||||
|       ret = OB_FILE_NOT_EXIST; | ||||
|       LOG_WARN("file not exist", K(ret), K(file_name)); | ||||
|     } else if (ObLoadFileLocation::OSS != load_args.load_file_storage_) { | ||||
|       load_args.file_name_ = file_name; | ||||
|     } else { | ||||
|       const char *p = nullptr; | ||||
|       ObString sub_file_name; | ||||
|       ObString cstyle_file_name; // ends with '\0' | ||||
|       char *full_path_buf = nullptr; | ||||
|       char *actual_path = nullptr; | ||||
|       if (OB_ISNULL(full_path_buf = static_cast<char *>(allocator_->alloc(MAX_PATH_SIZE)))) { | ||||
|         ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|         LOG_WARN("fail to allocate memory", K(ret)); | ||||
|       } | ||||
|       while (OB_SUCC(ret) && !file_name.empty()) { | ||||
|         p = file_name.find(','); | ||||
|         if (nullptr == p) { | ||||
|           sub_file_name = file_name; | ||||
|           cstyle_file_name = sub_file_name; | ||||
|           file_name.reset(); | ||||
|       if (ObLoadFileLocation::SERVER_DISK == load_args.load_file_storage_) { | ||||
|         load_args.file_name_ = file_name; | ||||
|         char *full_path_buf = nullptr; | ||||
|         char *actual_path = nullptr; | ||||
|         ObArray<ObString> match_array; | ||||
|         if (OB_ISNULL(full_path_buf = static_cast<char *>(allocator_->alloc(MAX_PATH_SIZE)))) { | ||||
|           ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|           LOG_WARN("fail to allocate memory", K(ret)); | ||||
|         } else if (exist_wildcard(file_name)) { | ||||
|           sub_file_name = file_name.trim_space_only(); | ||||
|           if (OB_FAIL(ob_write_string(*allocator_, sub_file_name, cstyle_file_name, true))) { | ||||
|             LOG_WARN("fail to write string", K(ret)); | ||||
|           } else { | ||||
|             glob_t glob_result; | ||||
|             int return_value = glob(cstyle_file_name.ptr(), 0, NULL, &glob_result); | ||||
|             if (return_value == GLOB_NOMATCH) { | ||||
|               ret = OB_FILE_NOT_EXIST; | ||||
|               LOG_WARN("No matches found for pattern", K(ret), K(ObString(cstyle_file_name))); | ||||
|             } else if (return_value != 0) { | ||||
|               ret = OB_ERR_SYS; | ||||
|               LOG_WARN("fail to glob", K(ObString(cstyle_file_name))); | ||||
|             } else { | ||||
|               for (size_t i = 0; OB_SUCC(ret) && i < glob_result.gl_pathc; ++i) { | ||||
|                 ObString match_file; | ||||
|                 if (OB_FAIL(ob_write_string(*allocator_, ObString(glob_result.gl_pathv[i]), match_file, true))) { | ||||
|                   LOG_WARN("fail to ob_write_string", K(ret)); | ||||
|                 } else if (OB_FAIL(match_array.push_back(match_file))) { | ||||
|                   LOG_WARN("fail to push back", K(ret)); | ||||
|                 } | ||||
|               } | ||||
|               globfree(&glob_result); | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           sub_file_name = file_name.split_on(p); | ||||
|           cstyle_file_name.reset(); | ||||
|           while (OB_SUCC(ret) && !file_name.empty()) { | ||||
|             p = file_name.find(','); | ||||
|             if (nullptr == p) { | ||||
|               sub_file_name = file_name.trim_space_only(); | ||||
|               cstyle_file_name = sub_file_name; | ||||
|               file_name.reset(); | ||||
|             } else { | ||||
|               sub_file_name = file_name.split_on(p).trim_space_only(); | ||||
|               cstyle_file_name.reset(); | ||||
|             } | ||||
|             if (!sub_file_name.empty()) { | ||||
|               if (cstyle_file_name.empty() && OB_FAIL(ob_write_string(*allocator_, sub_file_name, cstyle_file_name, true))) { | ||||
|                 LOG_WARN("fail to write string", K(ret)); | ||||
|               } else if (OB_FAIL(match_array.push_back(cstyle_file_name))) { | ||||
|                 LOG_WARN("fail to push back", K(ret)); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (!sub_file_name.empty()) { | ||||
|           if (cstyle_file_name.empty() && | ||||
|               OB_FAIL(ob_write_string(*allocator_, sub_file_name, cstyle_file_name, true))) { | ||||
|             LOG_WARN("fail to write string", KR(ret)); | ||||
|           } else if (ObLoadFileLocation::SERVER_DISK == load_args.load_file_storage_ && | ||||
|                      OB_ISNULL(actual_path = realpath(cstyle_file_name.ptr(), full_path_buf))) { | ||||
|         if (OB_SUCC(ret)) { | ||||
|           if (match_array.size() == 0) { | ||||
|             ret = OB_FILE_NOT_EXIST; | ||||
|             LOG_WARN("file not exist", K(ret), K(cstyle_file_name)); | ||||
|           } | ||||
|  | ||||
|           //security check for mysql mode | ||||
|           if (OB_SUCC(ret) && ObLoadFileLocation::SERVER_DISK == load_args.load_file_storage_) { | ||||
|             ObString secure_file_priv; | ||||
|             if (OB_FAIL(session_info_->get_secure_file_priv(secure_file_priv))) { | ||||
|               LOG_WARN("failed to get secure file priv", K(ret)); | ||||
|             } else if (OB_FAIL( | ||||
|                          ObResolverUtils::check_secure_path(secure_file_priv, actual_path))) { | ||||
|               LOG_WARN("failed to check secure path", K(ret), K(secure_file_priv), | ||||
|                        K(actual_path)); | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           if (OB_SUCC(ret)) { | ||||
|             if (ObLoadFileLocation::CLIENT_DISK == load_args.load_file_storage_ && load_args.file_iter_.count() != 0) { | ||||
|               ret = OB_NOT_SUPPORTED; | ||||
|               LOG_USER_ERROR(OB_NOT_SUPPORTED, "load multi files not supported"); | ||||
|             } else if (OB_FAIL(load_args.file_iter_.add_files(&cstyle_file_name))) { | ||||
|               LOG_WARN("fail to add files", KR(ret)); | ||||
|             LOG_WARN("files not exists", K(ret)); | ||||
|           } else { | ||||
|             for (int32_t i = 0; OB_SUCC(ret) && i < match_array.size(); i++) { | ||||
|               //security check for mysql mode | ||||
|               ObString secure_file_priv; | ||||
|               if (OB_ISNULL(actual_path = realpath(match_array[i].ptr(), full_path_buf))) { | ||||
|                 ret = OB_FILE_NOT_EXIST; | ||||
|                 LOG_WARN("file not exist", K(ret), K(i), K(match_array[i])); | ||||
|               } else if (OB_FAIL(session_info_->get_secure_file_priv(secure_file_priv))) { | ||||
|                 LOG_WARN("failed to get secure file priv", K(ret)); | ||||
|               } else if (OB_FAIL(ObResolverUtils::check_secure_path(secure_file_priv, actual_path))) { | ||||
|                 LOG_WARN("failed to check secure path", K(ret), K(secure_file_priv), K(actual_path)); | ||||
|               } else if (OB_FAIL(load_args.file_iter_.add_files(&match_array[i]))) { | ||||
|                 LOG_WARN("fail to add files", K(ret)); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       ObString temp_file_name = file_name.split_on('?'); | ||||
|       ObString storage_info; | ||||
|       if (OB_FAIL(ob_write_string(*allocator_, temp_file_name, load_args.file_name_, true))) { | ||||
|         LOG_WARN("fail to copy string", K(ret)); | ||||
|       } else if (OB_FAIL(ob_write_string(*allocator_, file_name, storage_info, true))) { | ||||
|         LOG_WARN("fail to copy string", K(ret)); | ||||
|       } else if (temp_file_name.length() <= 0 || storage_info.length() <= 0) { | ||||
|         ret = OB_INVALID_ARGUMENT; | ||||
|         LOG_USER_ERROR(OB_INVALID_ARGUMENT, "file name or access key"); | ||||
|       } else if (OB_FAIL(load_args.access_info_.set(load_args.file_name_.ptr(), storage_info.ptr()))) { | ||||
|         LOG_WARN("failed to set access info", K(ret)); | ||||
|       } else if (OB_FAIL(load_args.file_iter_.add_files(&load_args.file_name_))) { | ||||
|         LOG_WARN("fail to add files", KR(ret)); | ||||
|       } else if (ObLoadFileLocation::OSS == load_args.load_file_storage_) { | ||||
|         const char *storage_ptr = nullptr; | ||||
|         const char *file_ptr = nullptr; | ||||
|         if (OB_ISNULL(storage_ptr = file_name.reverse_find('?'))) { | ||||
|           ret = OB_INVALID_ARGUMENT; | ||||
|           LOG_USER_ERROR(OB_INVALID_ARGUMENT, "file name or access key"); | ||||
|         } else { | ||||
|           ObString temp_file_name = file_name.split_on(storage_ptr).trim_space_only(); | ||||
|           ObString storage_info; | ||||
|           bool matched = false; | ||||
|           ObString pattern; | ||||
|           ObString dir_path; | ||||
|           char *path = nullptr; | ||||
|           int64_t path_len = 0; | ||||
|           ObArray<ObString> file_list; | ||||
|           if (OB_FAIL(ob_write_string(*allocator_, temp_file_name, load_args.file_name_, true))) { | ||||
|             LOG_WARN("fail to copy string", K(ret)); | ||||
|           } else if (OB_FAIL(ob_write_string(*allocator_, file_name, storage_info, true))) { | ||||
|             LOG_WARN("fail to copy string", K(ret)); | ||||
|           } else if (temp_file_name.length() <= 0 || storage_info.length() <= 0) { | ||||
|             ret = OB_INVALID_ARGUMENT; | ||||
|             LOG_USER_ERROR(OB_INVALID_ARGUMENT, "file name or access key"); | ||||
|           } else if (OB_FAIL(load_args.access_info_.set(load_args.file_name_.ptr(), storage_info.ptr()))) { | ||||
|             LOG_WARN("failed to set access info", K(ret)); | ||||
|           } else if (OB_ISNULL(file_ptr = temp_file_name.reverse_find('/'))) { | ||||
|             ret = OB_INVALID_ARGUMENT; | ||||
|             LOG_USER_ERROR(OB_INVALID_ARGUMENT, "file name"); | ||||
|           } else { | ||||
|             dir_path.assign_ptr(temp_file_name.ptr(), file_ptr - temp_file_name.ptr() + 1); | ||||
|             pattern.assign_ptr(file_ptr + 1, temp_file_name.length() - dir_path.length()); | ||||
|             if (exist_wildcard(dir_path)) { | ||||
|               ret = OB_NOT_SUPPORTED; | ||||
|               LOG_WARN("directory does not support wildcard matching", K(ret)); | ||||
|             } else { | ||||
|               ObBackupIoAdapter adapter; | ||||
|               ObFileListArrayOp op(file_list, *allocator_); | ||||
|               if (OB_ISNULL(path = static_cast<char *>(allocator_->alloc(MAX_PATH_SIZE)))) { | ||||
|                 ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|                 LOG_WARN("fail to allocate memory", K(ret)); | ||||
|               } else if (OB_FAIL(databuff_printf(path, MAX_PATH_SIZE, path_len, "%.*s", | ||||
|                                                 dir_path.length(), dir_path.ptr()))) { | ||||
|                 LOG_WARN("fail to fill path", K(ret), K(path_len)); | ||||
|               } else if (OB_FAIL(adapter.list_files(ObString(path_len, path), &load_args.access_info_, op))) { | ||||
|                 LOG_WARN("fail to list files", K(ret)); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           for (int32_t i = 0; OB_SUCC(ret) && i < file_list.size(); i++) { | ||||
|             if (OB_FAIL(pattern_match(file_list[i], pattern, matched))) { | ||||
|               LOG_WARN("fail to pattern match", K(ret)); | ||||
|             } else if (matched) { | ||||
|               ObString match_file; | ||||
|               int64_t pos = path_len; | ||||
|               if (OB_FAIL(databuff_printf(path, MAX_PATH_SIZE, pos, "%.*s", | ||||
|                                           file_list[i].length(), file_list[i].ptr()))) { | ||||
|                 LOG_WARN("fail to fill path", K(ret)); | ||||
|               } else if (OB_FAIL(ob_write_string(*allocator_, ObString(pos, path), match_file, true))) { | ||||
|                 LOG_WARN("fail to copy string", K(ret)); | ||||
|               } else if (OB_FAIL(load_args.file_iter_.add_files(&match_file))) { | ||||
|                 LOG_WARN("fail to add files", K(ret)); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           if (OB_SUCC(ret) && load_args.file_iter_.count() == 0) { | ||||
|             ret = OB_BACKUP_FILE_NOT_EXIST; | ||||
|             LOG_WARN("No matches found for pattern", K(ret), K(pattern)); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         if (!file_name.empty()) { | ||||
|           if (OB_NOT_NULL(p = file_name.find(','))) { | ||||
|             ret = OB_NOT_SUPPORTED; | ||||
|             LOG_USER_ERROR(OB_NOT_SUPPORTED, "load multi files not supported"); | ||||
|           } else if (OB_FAIL(ob_write_string(*allocator_, file_name, cstyle_file_name, true))) { | ||||
|             LOG_WARN("fail to copy string", K(ret)); | ||||
|           } else if (OB_FAIL(load_args.file_iter_.add_files(&cstyle_file_name))) { | ||||
|             LOG_WARN("fail to add files", K(ret)); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -62,6 +62,9 @@ public: | ||||
|   int local_infile_enabled(bool &enabled) const; | ||||
|  | ||||
|   int check_trigger_constraint(const ObTableSchema *table_schema); | ||||
| private: | ||||
|   int pattern_match(const ObString& str, const ObString& pattern, bool &matched); | ||||
|   bool exist_wildcard(const ObString& str); | ||||
| private: | ||||
|   enum ParameterEnum { | ||||
|     ENUM_OPT_LOCAL = 0, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 obdev
					obdev