From 512dde7b55c154828c6e1264ac2ebd6aec1c5135 Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Thu, 5 Aug 2021 17:45:37 -0400 Subject: [PATCH] Handle property and dependency values of type BLOB in ListBundles. Per https://www.sqlite.org/datatype3.html#type_affinity: > In order to maximize compatibility between SQLite and other database > engines, and so that the example above will work on SQLite as it > does on other SQL database engines, SQLite supports the concept of > "type affinity" on columns. The type affinity of a column is the > recommended type for data stored in that column. The important idea > here is that the type is recommended, not required. Any column can > still store any type of data. It is just that some columns, given > the choice, will prefer to use one storage class over another. The > preferred storage class for a column is called its "affinity". Even though the properties and dependencies tables are created with column affinity TEXT on both their "type" and "value" columns, SQLite does not require values stored in those columns to have that type. The query backing the registry.ListBundles API recently began using the json_object function from the json1 SQLite extension (https://www.sqlite.org/json1.html#jobj), which does not support arguments of type BLOB. The docs state: > If any argument to json_object() is a BLOB then an error is thrown. But it seems that no error is actually being returned. Instead, the result set it empty. This may be an issue with the SQLite driver? It seems to produce an error in sqlite3's interactive mode. Signed-off-by: Ben Luddy Upstream-repository: operator-registry Upstream-commit: c2fc1fd45d64401b512969f83011868940d83a59 --- staging/operator-registry/pkg/sqlite/query.go | 4 +-- .../pkg/sqlite/query_sql_test.go | 31 +++++++++++++++++++ .../operator-registry/pkg/sqlite/query.go | 4 +-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/staging/operator-registry/pkg/sqlite/query.go b/staging/operator-registry/pkg/sqlite/query.go index fb24204941..1a45d9895e 100644 --- a/staging/operator-registry/pkg/sqlite/query.go +++ b/staging/operator-registry/pkg/sqlite/query.go @@ -991,12 +991,12 @@ tip (depth) AS ( GROUP BY all_entry.operatorbundle_name, all_entry.package_name, all_entry.channel_name ), merged_properties (bundle_name, merged) AS ( - SELECT operatorbundle_name, json_group_array(json_object('type', properties.type, 'value', properties.value)) + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(properties.type AS TEXT), 'value', CAST(properties.value AS TEXT))) FROM properties GROUP BY operatorbundle_name ), merged_dependencies (bundle_name, merged) AS ( - SELECT operatorbundle_name, json_group_array(json_object('type', dependencies.type, 'value', CAST(dependencies.value AS TEXT))) + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(dependencies.type AS TEXT), 'value', CAST(dependencies.value AS TEXT))) FROM dependencies GROUP BY operatorbundle_name ) diff --git a/staging/operator-registry/pkg/sqlite/query_sql_test.go b/staging/operator-registry/pkg/sqlite/query_sql_test.go index 73a19db705..ff33a91a99 100644 --- a/staging/operator-registry/pkg/sqlite/query_sql_test.go +++ b/staging/operator-registry/pkg/sqlite/query_sql_test.go @@ -155,6 +155,37 @@ func TestListBundlesQuery(t *testing.T) { require.False(rows.Next()) }, }, + { + Name: "properties and depdendencies columns may be stored as sqlite type blob", + OmitManfests: true, + Setup: func(t *testing.T, db *sql.DB) { + for _, stmt := range []string{ + `insert into package (name, default_channel) values ("package", "channel")`, + `insert into channel (name, package_name, head_operatorbundle_name) values ("channel", "package", "bundle")`, + `insert into operatorbundle (name, bundle) values ("bundle-a", "{}")`, + `insert into channel_entry (package_name, channel_name, operatorbundle_name, entry_id, depth) values ("package", "channel", "bundle-a", 1, 0)`, + `insert into properties (type, value, operatorbundle_name) values (CAST("blob_ptype" AS BLOB), CAST("blob_pvalue" AS BLOB), "bundle-a")`, + `insert into dependencies (type, value, operatorbundle_name) values (CAST("blob_dtype" AS BLOB), CAST("blob_dvalue" AS BLOB), "bundle-a")`, + } { + if _, err := db.Exec(stmt); err != nil { + t.Fatalf("unexpected error executing setup statements: %v", err) + } + } + + }, + Expect: func(t *testing.T, rows *sql.Rows) { + require := require.New(t) + require.True(rows.Next()) + var ( + props, deps sql.NullString + c interface{} + ) + require.NoError(rows.Scan(&c, &c, &c, &c, &c, &c, &c, &c, &c, &c, &deps, &props)) + require.Equal(sql.NullString{Valid: true, String: `[{"type":"blob_ptype","value":"blob_pvalue"}]`}, props) + require.Equal(sql.NullString{Valid: true, String: `[{"type":"blob_dtype","value":"blob_dvalue"}]`}, deps) + require.False(rows.Next()) + }, + }, { Name: "manifests not omitted with bundlepath", OmitManfests: true, diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go index fb24204941..1a45d9895e 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go @@ -991,12 +991,12 @@ tip (depth) AS ( GROUP BY all_entry.operatorbundle_name, all_entry.package_name, all_entry.channel_name ), merged_properties (bundle_name, merged) AS ( - SELECT operatorbundle_name, json_group_array(json_object('type', properties.type, 'value', properties.value)) + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(properties.type AS TEXT), 'value', CAST(properties.value AS TEXT))) FROM properties GROUP BY operatorbundle_name ), merged_dependencies (bundle_name, merged) AS ( - SELECT operatorbundle_name, json_group_array(json_object('type', dependencies.type, 'value', CAST(dependencies.value AS TEXT))) + SELECT operatorbundle_name, json_group_array(json_object('type', CAST(dependencies.type AS TEXT), 'value', CAST(dependencies.value AS TEXT))) FROM dependencies GROUP BY operatorbundle_name )