Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extension Updating #11677

Merged
merged 62 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d783f00
add syntax to install a versioned extension
samansmink Jan 2, 2024
867547a
fixes to extension versioned install
samansmink Feb 2, 2024
b8657dc
duplicate header
samansmink Feb 2, 2024
d55942b
basic idea of extension updating working
samansmink Mar 6, 2024
445d9b1
extension updating + small refactor
samansmink Mar 7, 2024
308bc10
Merge branch 'main' into install-extension-version
samansmink Apr 3, 2024
22a0b33
Merge branch 'extension_metadata' into install-extension-version-merged
samansmink Apr 10, 2024
0d22196
add repository aliasing
samansmink Apr 10, 2024
c6e0337
rework extension repository mechanism slightly
samansmink Apr 10, 2024
1f0386b
more extension updating improvements
samansmink Apr 15, 2024
5059c5b
switch to dedicated opeator for update extensions
samansmink Apr 15, 2024
228ebc2
add CI test for succesful update extensions statement
samansmink Apr 15, 2024
1de4405
format
samansmink Apr 15, 2024
f00322b
some minor extension updating fixes
samansmink Apr 15, 2024
f775594
remove old test
samansmink Apr 15, 2024
2f294b1
add errors to incorrect version installation as well
samansmink Apr 16, 2024
5cd6002
format
samansmink Apr 16, 2024
6f1bde6
improve extension versioning/updating CI
samansmink Apr 16, 2024
70d416d
disable broken test for now
samansmink Apr 16, 2024
c6082bc
fix broken test
samansmink Apr 16, 2024
96e5ff8
remove old code
samansmink Apr 16, 2024
36299a8
Merge branch 'main' into install-extension-version-merged
samansmink Apr 16, 2024
96f8922
Extension API: Add optional member Version()
carlopi Apr 16, 2024
2a55929
Use ext.Version() to handle versioning info also for built-in extensions
carlopi Apr 16, 2024
c32e54e
CMake: Propagate EXT_VERSION_NAME to hold the CMake computed version …
carlopi Apr 16, 2024
ae5d3eb
In-tree extensions to be passed the versioning info
carlopi Apr 16, 2024
7099214
forward define for python
samansmink Apr 17, 2024
f8a4dac
re-enable test assertion
samansmink Apr 17, 2024
21f5e7e
small CI fixes
samansmink Apr 17, 2024
4f0088a
wip
samansmink Apr 19, 2024
f4d0597
Merge branch 'main' into install-extension-version-merged
samansmink May 10, 2024
5f12217
fix merge conflict issue
samansmink May 10, 2024
df7c860
add accidentally removed cast
samansmink May 13, 2024
4cf2ccb
Merge branch 'main' into install-extension-version-merged
samansmink May 13, 2024
4bcc31e
cleanup changes to extension updating
samansmink May 13, 2024
7d684db
fixing ci for extension update PR
samansmink May 13, 2024
99f87da
add extension version detection
samansmink May 13, 2024
7ba67d3
fix out-of-tree version-detection
samansmink May 14, 2024
5bb8b50
dont set EXT_VERSION_ define if no version is available
samansmink May 14, 2024
09a19cd
add auto-loading for extension install over httpfs
samansmink May 14, 2024
8efd4a5
format
samansmink May 14, 2024
1e8ebdd
fix install gzipped from https urls
samansmink May 15, 2024
9c26dc2
better error handling for malformed or missing info files
samansmink May 15, 2024
9422b49
small tweak to extension install write order
samansmink May 16, 2024
18d0edb
switch to explicit difference between repo and repo url
samansmink May 16, 2024
ee1c21e
add test cases for malformed and missing info files
samansmink May 16, 2024
4aefceb
add gzipped extension install to non-http install
samansmink May 16, 2024
b3c471f
add http tests as well
samansmink May 16, 2024
cc77eec
fix ci issue and fix updating over https issue
samansmink May 16, 2024
76acf25
fix extension updating job
samansmink May 16, 2024
c510994
build with tpch
samansmink May 16, 2024
8f484a5
clang tidy, speed up decompress
samansmink May 17, 2024
e0b4e89
small extension updating fixes
samansmink May 17, 2024
3ae45d6
format
samansmink May 17, 2024
1736368
several smaller fixes to extension installation and updating
samansmink May 17, 2024
cdb1c4d
catch install without force from different repo
samansmink May 17, 2024
52ebf66
fix memory leak on exceptions in listfiles
samansmink May 17, 2024
d02f157
format
samansmink May 17, 2024
0ed81d0
add no_extension_autoloading
samansmink May 18, 2024
529759a
Merge branch 'main' into install-extension-version-merged
samansmink May 19, 2024
d14607e
fix generated_extensions script to handle csv format instead of txt f…
samansmink May 19, 2024
b530912
small ci fixes
samansmink May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add errors to incorrect version installation as well
  • Loading branch information
samansmink committed Apr 16, 2024
commit 2f294b17edfbd77f161976b12d4ba9b0ea54ad75
3 changes: 3 additions & 0 deletions src/include/duckdb/main/extension.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct ParsedExtensionMetaData {
bool AppearsValid() {
return magic_value == EXPECTED_MAGIC_VALUE;
}

// Returns an error string describing which parts of the metadata are mismatcheds
string GetInvalidMetadataError();
};

} // namespace duckdb
55 changes: 55 additions & 0 deletions src/main/extension.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,63 @@
#include "duckdb/main/extension.hpp"
#include "duckdb/common/string_util.hpp"
#include "duckdb/main/extension_helper.hpp"


namespace duckdb {

Extension::~Extension() {
}

static string PrettyPrintString(const string &s) {
string res = "";
for (auto c : s) {
if (StringUtil::CharacterIsAlpha(c) || StringUtil::CharacterIsDigit(c) || c == '_' || c == '-' || c == ' ' ||
c == '.') {
res += c;
} else {
uint8_t value = c;
res += "\\x";
uint8_t first = value / 16;
if (first < 10) {
res.push_back((char)('0' + first));
} else {
res.push_back((char)('a' + first - 10));
}
uint8_t second = value % 16;
if (second < 10) {
res.push_back((char)('0' + second));
} else {
res.push_back((char)('a' + second - 10));
}
}
}
return res;
}

string ParsedExtensionMetaData::GetInvalidMetadataError() {
const string engine_version = string(ExtensionHelper::GetVersionDirectoryName());
const string engine_platform = string(DuckDB::Platform());

if (!AppearsValid()) {
return "The file is not a DuckDB extension. The metadata at the end of the file is invalid";
}

string result;
if (engine_version != duckdb_version) {
result += StringUtil::Format("The file was built for DuckDB version '%s', but we can only load extensions built for DuckDB version '%s'.",
PrettyPrintString(duckdb_version), engine_version);
}
if (engine_platform != platform) {
if (!result.empty()) {
result += "Also, t";
} else {
result += "T";
}
result += StringUtil::Format("he file was built for the platform '%s', but we can only load extensions built for platform '%s'.",
PrettyPrintString(platform), engine_platform);
}

return result;
}

} // namespace duckdb
27 changes: 20 additions & 7 deletions src/main/extension/extension_install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,23 @@ string ExtensionHelper::ExtensionFinalizeUrlTemplate(const string &url_template,
return url;
}

static void CheckExtensionMetadataOnInstall(DBConfig &config, void *in_buffer, idx_t file_size, ExtensionInstallInfo &info, const string &extension_name) {
if (file_size < ParsedExtensionMetaData::FOOTER_SIZE) {
throw IOException("Failed to install '%s', file too small to be a valid DuckDB extension!", extension_name);
}

auto parsed_metadata = ExtensionHelper::ParseExtensionMetaData(static_cast<char *>(in_buffer) +
(file_size - ParsedExtensionMetaData::FOOTER_SIZE));

auto metadata_mismatch_error = parsed_metadata.GetInvalidMetadataError();

if (!metadata_mismatch_error.empty() && !config.options.allow_extensions_metadata_mismatch) {
throw IOException("Failed to install '%s', %s", extension_name, metadata_mismatch_error);
}

info.version = parsed_metadata.extension_version;
}

static void WriteExtensionFiles(FileSystem &fs, const string &temp_path, const string &local_extension_path,
void *in_buffer, idx_t file_size, bool force_install, ExtensionInstallInfo &info) {
// Write files
Expand All @@ -242,13 +259,6 @@ static void WriteExtensionFiles(FileSystem &fs, const string &temp_path, const s
}
fs.MoveFile(temp_path, local_extension_path);

// This is the moment to parse the metadata to get the version info from the buffer
auto parsed_metadata = ExtensionHelper::ParseExtensionMetaData(static_cast<char *>(in_buffer) +
(file_size - ParsedExtensionMetaData::FOOTER_SIZE));
if (parsed_metadata.AppearsValid()) {
info.version = parsed_metadata.extension_version;
}

// Write metadata
auto metadata_tmp_path = temp_path + ".info";
auto metadata_file_path = local_extension_path + ".info";
Expand Down Expand Up @@ -281,6 +291,7 @@ static unique_ptr<ExtensionInstallInfo> DirectInstallExtension(DBConfig &config,
auto in_buffer = ReadExtensionFileFromDisk(fs, file, file_size);

ExtensionInstallInfo info;
CheckExtensionMetadataOnInstall(config, (void *)in_buffer.get(), file_size, info, extension_name);

if (repository_url.empty()) {
info.mode = ExtensionInstallMode::CUSTOM_PATH;
Expand Down Expand Up @@ -337,6 +348,8 @@ static unique_ptr<ExtensionInstallInfo> InstallFromHttpUrl(DBConfig &config, con
auto decompressed_body = GZipFileSystem::UncompressGZIPString(res->body);

ExtensionInstallInfo info;
CheckExtensionMetadataOnInstall(config, (void *)decompressed_body.data(), decompressed_body.size(), info, extension_name);

info.mode = ExtensionInstallMode::REPOSITORY;
info.full_path = url;
info.repository_url = repository_url;
Expand Down
52 changes: 3 additions & 49 deletions src/main/extension/extension_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,32 +65,6 @@ static string FilterZeroAtEnd(string s) {
return s;
}

static string PrettyPrintString(const string &s) {
string res = "";
for (auto c : s) {
if (StringUtil::CharacterIsAlpha(c) || StringUtil::CharacterIsDigit(c) || c == '_' || c == '-' || c == ' ' ||
c == '.') {
res += c;
} else {
uint8_t value = c;
res += "\\x";
uint8_t first = value / 16;
if (first < 10) {
res.push_back((char)('0' + first));
} else {
res.push_back((char)('a' + first - 10));
}
uint8_t second = value % 16;
if (second < 10) {
res.push_back((char)('0' + second));
} else {
res.push_back((char)('a' + second - 10));
}
}
}
return res;
}

ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(const char *metadata) {
ParsedExtensionMetaData result;

Expand Down Expand Up @@ -250,32 +224,12 @@ bool ExtensionHelper::TryInitialLoad(DBConfig &config, FileSystem &fs, const str
// Parse the extension metadata from the extension binary
auto parsed_metadata = ParseExtensionMetaData(*handle);

string metadata_mismatch_error;
const string engine_version = string(ExtensionHelper::GetVersionDirectoryName());
const string engine_platform = string(DuckDB::Platform());
auto metadata_mismatch_error = parsed_metadata.GetInvalidMetadataError();

// Check the parsed
if (!parsed_metadata.AppearsValid()) {
// metadata do not looks right, add this to the error message
metadata_mismatch_error = StringUtil::Format("\nFile '%s' is not a DuckDB extension. The metadata at the end of the file is invalid. "
"This version of DuckDB can only load extensions that are compiled for DuckDB "
"version '%s', platform '%s'.", handle->path, engine_version, engine_platform);
} else if (engine_version != parsed_metadata.duckdb_version || engine_platform != parsed_metadata.platform) {
metadata_mismatch_error = StringUtil::Format("\nFile '%s' is a DuckDB extension, but the metadata does not match:", handle->path);

if (engine_version != parsed_metadata.duckdb_version) {
metadata_mismatch_error +=
"\n" + StringUtil::Format("\nThe file was built for DuckDB version '%s', but we can only load extensions built for DuckDB version '%s'.",
PrettyPrintString(parsed_metadata.duckdb_version), engine_version);
}
if (engine_platform != parsed_metadata.platform) {
metadata_mismatch_error +=
"\n" + StringUtil::Format("\nThe file was built for the platform '%s', but we can only load extensions built for platform '%s'.",
PrettyPrintString(parsed_metadata.platform), engine_platform);
}
if (!metadata_mismatch_error.empty()) {
metadata_mismatch_error = StringUtil::Format("Failed to load '%s'",extension) + "\n" + metadata_mismatch_error;
}


if (!config.options.allow_unsigned_extensions) {
bool signature_valid = CheckExtensionSignature(*handle, parsed_metadata);

Expand Down