| 165 | |
| 166 | |
| 167 | void ExternalTablesHandler::handlePart(const Poco::Net::MessageHeader & header, ReadBuffer & stream) |
| 168 | { |
| 169 | /// After finishing this function we will be ready to receive the next file, for this we clear all the information received. |
| 170 | /// We should use SCOPE_EXIT because read_buffer should be reset correctly if there will be an exception. |
| 171 | SCOPE_EXIT(clear()); |
| 172 | |
| 173 | const Settings & settings = getContext()->getSettingsRef(); |
| 174 | |
| 175 | if (settings[Setting::http_max_multipart_form_data_size]) |
| 176 | read_buffer = std::make_unique<LimitReadBuffer>( |
| 177 | stream, |
| 178 | LimitReadBuffer::Settings{ |
| 179 | .read_no_more = settings[Setting::http_max_multipart_form_data_size], |
| 180 | .expect_eof = true, |
| 181 | .excetion_hint = "the maximum size of multipart/form-data. This limit can be tuned by 'http_max_multipart_form_data_size' setting", |
| 182 | }); |
| 183 | else |
| 184 | read_buffer = wrapReadBufferReference(stream); |
| 185 | |
| 186 | /// Retrieve a collection of parameters from MessageHeader |
| 187 | Poco::Net::NameValueCollection content; |
| 188 | std::string label; |
| 189 | Poco::Net::MessageHeader::splitParameters(header.get("Content-Disposition"), label, content); |
| 190 | |
| 191 | /// Get parameters |
| 192 | name = content.get("name", "_data"); |
| 193 | format = params.get(name + "_format", "TabSeparated"); |
| 194 | |
| 195 | if (params.has(name + "_structure")) |
| 196 | parseStructureFromStructureField(params.get(name + "_structure")); |
| 197 | else if (params.has(name + "_types")) |
| 198 | parseStructureFromTypesField(params.get(name + "_types")); |
| 199 | else |
| 200 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 201 | "Neither structure nor types have not been provided for external table {}. " |
| 202 | "Use fields {}_structure or {}_types to do so.", name, name, name); |
| 203 | |
| 204 | ExternalTableDataPtr data = getData(getContext()); |
| 205 | |
| 206 | auto temporary_id = StorageID::createEmpty(); |
| 207 | temporary_id.table_name = data->table_name; |
| 208 | |
| 209 | auto resolved = getContext()->tryResolveStorageID(temporary_id, Context::ResolveExternal); |
| 210 | |
| 211 | StoragePtr storage; |
| 212 | if (resolved) |
| 213 | { |
| 214 | LOG_TEST(getLogger("ExternalTablesHandler"), "Using existing table {} for external data", temporary_id.getNameForLogs()); |
| 215 | storage = DatabaseCatalog::instance().getTable(resolved, getContext()); |
| 216 | } |
| 217 | else |
| 218 | { |
| 219 | LOG_TEST(getLogger("ExternalTablesHandler"), "Creating temporary table {} for external data", temporary_id.getNameForLogs()); |
| 220 | NamesAndTypesList columns = sample_block.getNamesAndTypesList(); |
| 221 | auto temporary_table = TemporaryTableHolder(getContext(), ColumnsDescription{columns}, {}); |
| 222 | storage = temporary_table.getTable(); |
| 223 | getContext()->addExternalTable(temporary_id.table_name, std::move(temporary_table)); |
| 224 | } |
nothing calls this directly
no test coverage detected