From f5f96f6fe1c93410115c2c8dece213dd2e500041 Mon Sep 17 00:00:00 2001 From: Zhiqiang Liu Date: Mon, 27 Jul 2020 16:02:40 +0800 Subject: [PATCH] gom: backport upstream patches-epoch1 gom: backport upstream patches-epoch1 Signed-off-by: Zhiqiang Liu --- ...sts-Add-test-for-invalid-table-names.patch | 253 ++++++++++++++++++ ...ate-header-to-list-reserved-keywords.patch | 163 +++++++++++ ...er-a-table-name-is-valid-before-sett.patch | 54 ++++ ...for-assertion-due-to-invalid-table-n.patch | 38 +++ ...L-GDateTimes-in-the-database-as-NULL.patch | 65 +++++ gom.spec | 12 +- 6 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 0001-tests-Add-test-for-invalid-table-names.patch create mode 100644 0002-gom-Add-a-private-header-to-list-reserved-keywords.patch create mode 100644 0003-gom-Verify-whether-a-table-name-is-valid-before-sett.patch create mode 100644 0004-tests-And-check-for-assertion-due-to-invalid-table-n.patch create mode 100644 0005-gom-Store-NULL-GDateTimes-in-the-database-as-NULL.patch diff --git a/0001-tests-Add-test-for-invalid-table-names.patch b/0001-tests-Add-test-for-invalid-table-names.patch new file mode 100644 index 0000000..dc182e1 --- /dev/null +++ b/0001-tests-Add-test-for-invalid-table-names.patch @@ -0,0 +1,253 @@ +From 4ce0cb6cadfe6f08e26f2e88ad7f002bc0d775ac Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Wed, 9 Aug 2017 12:32:51 +0200 +Subject: [PATCH 01/29] tests: Add test for invalid table names + +https://bugzilla.gnome.org/show_bug.cgi?id=785983 +--- + tests/meson.build | 1 + + tests/test-gom-table-name.c | 220 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 221 insertions(+) + create mode 100644 tests/test-gom-table-name.c + +diff --git a/tests/meson.build b/tests/meson.build +index 340e8c1..1df4884 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -6,6 +6,7 @@ tests = [ + 'test-gom-migration', + 'test-gom-repository', + 'test-gom-sorting', ++ 'test-gom-table-name', + 'test-gom-update', + ] + +diff --git a/tests/test-gom-table-name.c b/tests/test-gom-table-name.c +new file mode 100644 +index 0000000..7c099d0 +--- /dev/null ++++ b/tests/test-gom-table-name.c +@@ -0,0 +1,220 @@ ++#include ++#include ++ ++enum { ++ PROP_0, ++ PROP_ID, ++ PROP_FIRST_NAME, ++ PROP_SURNAME, ++ LAST_PROP ++}; ++ ++#define ITEM_TYPE_RESOURCE (item_resource_get_type()) ++#define ITEM_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ITEM_TYPE_RESOURCE, ItemResource)) ++#define ITEM_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITEM_TYPE_RESOURCE, ItemResourceClass)) ++#define ITEM_IS_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ITEM_TYPE_RESOURCE)) ++#define ITEM_IS_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITEM_TYPE_RESOURCE)) ++#define ITEM_RESOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITEM_TYPE_RESOURCE, ItemResourceClass)) ++ ++typedef struct { ++ int id; ++ char *first_name; ++ char *surname; ++} ItemResourcePrivate; ++ ++typedef struct { ++ GomResource parent; ++ ItemResourcePrivate *priv; ++} ItemResource; ++ ++typedef struct { ++ GomResourceClass parent_class; ++} ItemResourceClass; ++ ++GType item_resource_get_type(void); ++ ++G_DEFINE_TYPE(ItemResource, item_resource, GOM_TYPE_RESOURCE) ++ ++static GParamSpec *item_specs[LAST_PROP]; ++ ++static void ++item_resource_finalize (GObject *object) ++{ ++ ItemResource *resource = ITEM_RESOURCE(object); ++ g_clear_pointer(&resource->priv->first_name, g_free); ++ g_clear_pointer(&resource->priv->surname, g_free); ++} ++ ++static void ++item_resource_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ ItemResource *resource = ITEM_RESOURCE(object); ++ ++ switch (prop_id) { ++ case PROP_ID: ++ g_value_set_int(value, resource->priv->id); ++ break; ++ case PROP_FIRST_NAME: ++ g_value_set_string(value, resource->priv->first_name); ++ break; ++ case PROP_SURNAME: ++ g_value_set_string(value, resource->priv->surname); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); ++ } ++} ++ ++static void ++item_resource_set_property (GObject *object, ++ guint prop_id, ++ const GValue *value, ++ GParamSpec *pspec) ++{ ++ ItemResource *resource = ITEM_RESOURCE(object); ++ ++ switch (prop_id) { ++ case PROP_ID: ++ resource->priv->id = g_value_get_int(value); ++ break; ++ case PROP_FIRST_NAME: ++ g_clear_pointer(&resource->priv->first_name, g_free); ++ resource->priv->first_name = g_value_dup_string(value); ++ break; ++ case PROP_SURNAME: ++ g_clear_pointer(&resource->priv->surname, g_free); ++ resource->priv->surname = g_value_dup_string(value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); ++ } ++} ++ ++static void ++item_resource_class_init (ItemResourceClass *klass) ++{ ++ GObjectClass *object_class; ++ GomResourceClass *resource_class; ++ ++ object_class = G_OBJECT_CLASS(klass); ++ object_class->finalize = item_resource_finalize; ++ object_class->get_property = item_resource_get_property; ++ object_class->set_property = item_resource_set_property; ++ g_type_class_add_private(object_class, sizeof(ItemResourcePrivate)); ++ ++ resource_class = GOM_RESOURCE_CLASS(klass); ++ /* Invalid table name */ ++ gom_resource_class_set_table(resource_class, "insert"); ++ ++ item_specs[PROP_ID] = g_param_spec_int("id", ++ "ID", ++ "The ID for the item.", ++ G_MININT, G_MAXINT, 0, ++ G_PARAM_READWRITE); ++ g_object_class_install_property(object_class, PROP_ID, ++ item_specs[PROP_ID]); ++ gom_resource_class_set_primary_key(resource_class, "id"); ++ ++ item_specs[PROP_FIRST_NAME] = g_param_spec_string("first-name", ++ "First name", ++ "The First name for the item.", ++ NULL, ++ G_PARAM_READWRITE); ++ g_object_class_install_property(object_class, PROP_FIRST_NAME, ++ item_specs[PROP_FIRST_NAME]); ++ ++ item_specs[PROP_SURNAME] = g_param_spec_string("surname", ++ "Surname", ++ "The Surname for the item.", ++ NULL, ++ G_PARAM_READWRITE); ++ g_object_class_install_property(object_class, PROP_SURNAME, ++ item_specs[PROP_SURNAME]); ++} ++ ++static void ++item_resource_init (ItemResource *resource) ++{ ++ resource->priv = G_TYPE_INSTANCE_GET_PRIVATE(resource, ++ ITEM_TYPE_RESOURCE, ++ ItemResourcePrivate); ++} ++ ++static void ++table_name (void) ++{ ++ GomAdapter *adapter; ++ GError *error = NULL; ++ gboolean ret; ++ GomRepository *repository; ++ GList *object_types; ++ GValue value = { 0, }; ++ GomFilter *filter; ++ char *s1, *s2; ++ ItemResource *it; ++ ++ adapter = gom_adapter_new(); ++ //ret = gom_adapter_open_sync(adapter, "file:test.db", &error); ++ ret = gom_adapter_open_sync(adapter, ":memory:", &error); ++ g_assert_no_error(error); ++ g_assert(ret); ++ ++ repository = gom_repository_new(adapter); ++ ++ object_types = g_list_prepend(NULL, GINT_TO_POINTER(ITEM_TYPE_RESOURCE)); ++ ret = gom_repository_automatic_migrate_sync(repository, 1, object_types, &error); ++ g_assert_no_error(error); ++ g_assert(ret); ++ ++ it = g_object_new (ITEM_TYPE_RESOURCE, ++ "repository", repository, ++ "first-name", "First name", ++ "surname", "Surname", ++ NULL); ++ ret = gom_resource_save_sync(GOM_RESOURCE(it), &error); ++ g_assert(ret); ++ g_assert_no_error(error); ++ g_object_unref(it); ++ ++ g_value_init(&value, G_TYPE_STRING); ++ g_value_set_string(&value, "First name"); ++ filter = gom_filter_new_eq(ITEM_TYPE_RESOURCE, "first-name", &value); ++ g_value_unset(&value); ++ ++ it = ITEM_RESOURCE (gom_repository_find_one_sync(repository, ++ ITEM_TYPE_RESOURCE, ++ filter, ++ &error)); ++ g_assert_no_error(error); ++ g_assert(it); ++ g_object_unref(filter); ++ ++ g_object_get(it, ++ "first-name", &s1, ++ "surname", &s2, ++ NULL); ++ g_object_unref(it); ++ ++ g_assert_cmpstr(s1, ==, "First name"); ++ g_assert_cmpstr(s2, ==, "Surname"); ++ g_free(s1); ++ g_free(s2); ++ ++ ret = gom_adapter_close_sync(adapter, &error); ++ g_assert_no_error(error); ++ g_assert(ret); ++ ++ g_object_unref(repository); ++ g_object_unref(adapter); ++} ++ ++gint ++main (int argc, char **argv) ++{ ++ g_test_init(&argc, &argv, NULL); ++ g_test_add_func("/GomRepository/table_name", table_name); ++ return g_test_run(); ++} +-- +2.21.1 (Apple Git-122.3) + diff --git a/0002-gom-Add-a-private-header-to-list-reserved-keywords.patch b/0002-gom-Add-a-private-header-to-list-reserved-keywords.patch new file mode 100644 index 0000000..8a281a5 --- /dev/null +++ b/0002-gom-Add-a-private-header-to-list-reserved-keywords.patch @@ -0,0 +1,163 @@ +From 1df4aa6cd71564ee99103a2e93e93e8a97fdaaed Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Wed, 9 Aug 2017 12:48:00 +0200 +Subject: [PATCH 02/29] gom: Add a private header to list reserved keywords + +https://bugzilla.gnome.org/show_bug.cgi?id=785983 +--- + gom/meson.build | 1 + + gom/reserved-keywords.h | 130 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 131 insertions(+) + create mode 100644 gom/reserved-keywords.h + +diff --git a/gom/meson.build b/gom/meson.build +index 90e1e7d..f27b364 100644 +--- a/gom/meson.build ++++ b/gom/meson.build +@@ -28,6 +28,7 @@ gom_headers = [ + + gom_private_headers = [ + 'gom-resource-priv.h', ++ 'reserved-keywords.h', + ] + + install_headers(gom_headers, +diff --git a/gom/reserved-keywords.h b/gom/reserved-keywords.h +new file mode 100644 +index 0000000..0eb1c95 +--- /dev/null ++++ b/gom/reserved-keywords.h +@@ -0,0 +1,130 @@ ++/* Partially generated with the very brittle: ++ * for i in `wget -O- https://sqlite.org/lang_keywords.html | grep '
  • ' | sed 's,
  • ,,' | sed 's,
  • ,,' | grep -v '<'` ; do printf '\t"%s",\n' $i >> gom/reserved-keywords.h ; done ++ */ ++ ++static const char* reserved_keywords[] = { ++ "ABORT", ++ "ACTION", ++ "ADD", ++ "AFTER", ++ "ALL", ++ "ALTER", ++ "ANALYZE", ++ "AND", ++ "AS", ++ "ASC", ++ "ATTACH", ++ "AUTOINCREMENT", ++ "BEFORE", ++ "BEGIN", ++ "BETWEEN", ++ "BY", ++ "CASCADE", ++ "CASE", ++ "CAST", ++ "CHECK", ++ "COLLATE", ++ "COLUMN", ++ "COMMIT", ++ "CONFLICT", ++ "CONSTRAINT", ++ "CREATE", ++ "CROSS", ++ "CURRENT_DATE", ++ "CURRENT_TIME", ++ "CURRENT_TIMESTAMP", ++ "DATABASE", ++ "DEFAULT", ++ "DEFERRABLE", ++ "DEFERRED", ++ "DELETE", ++ "DESC", ++ "DETACH", ++ "DISTINCT", ++ "DROP", ++ "EACH", ++ "ELSE", ++ "END", ++ "ESCAPE", ++ "EXCEPT", ++ "EXCLUSIVE", ++ "EXISTS", ++ "EXPLAIN", ++ "FAIL", ++ "FOR", ++ "FOREIGN", ++ "FROM", ++ "FULL", ++ "GLOB", ++ "GROUP", ++ "HAVING", ++ "IF", ++ "IGNORE", ++ "IMMEDIATE", ++ "IN", ++ "INDEX", ++ "INDEXED", ++ "INITIALLY", ++ "INNER", ++ "INSERT", ++ "INSTEAD", ++ "INTERSECT", ++ "INTO", ++ "IS", ++ "ISNULL", ++ "JOIN", ++ "KEY", ++ "LEFT", ++ "LIKE", ++ "LIMIT", ++ "MATCH", ++ "NATURAL", ++ "NO", ++ "NOT", ++ "NOTNULL", ++ "NULL", ++ "OF", ++ "OFFSET", ++ "ON", ++ "OR", ++ "ORDER", ++ "OUTER", ++ "PLAN", ++ "PRAGMA", ++ "PRIMARY", ++ "QUERY", ++ "RAISE", ++ "RECURSIVE", ++ "REFERENCES", ++ "REGEXP", ++ "REINDEX", ++ "RELEASE", ++ "RENAME", ++ "REPLACE", ++ "RESTRICT", ++ "RIGHT", ++ "ROLLBACK", ++ "ROW", ++ "SAVEPOINT", ++ "SELECT", ++ "SET", ++ "TABLE", ++ "TEMP", ++ "TEMPORARY", ++ "THEN", ++ "TO", ++ "TRANSACTION", ++ "TRIGGER", ++ "UNION", ++ "UNIQUE", ++ "UPDATE", ++ "USING", ++ "VACUUM", ++ "VALUES", ++ "VIEW", ++ "VIRTUAL", ++ "WHEN", ++ "WHERE", ++ "WITH", ++ "WITHOUT" ++}; +-- +2.21.1 (Apple Git-122.3) + diff --git a/0003-gom-Verify-whether-a-table-name-is-valid-before-sett.patch b/0003-gom-Verify-whether-a-table-name-is-valid-before-sett.patch new file mode 100644 index 0000000..3660787 --- /dev/null +++ b/0003-gom-Verify-whether-a-table-name-is-valid-before-sett.patch @@ -0,0 +1,54 @@ +From 8e1777724a34aaa0f7361017a145e539318eedeb Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Wed, 9 Aug 2017 12:52:08 +0200 +Subject: [PATCH 03/29] gom: Verify whether a table name is valid before + setting it + +https://bugzilla.gnome.org/show_bug.cgi?id=785983 +--- + gom/gom-resource.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/gom/gom-resource.c b/gom/gom-resource.c +index 25d934e..2d2b495 100644 +--- a/gom/gom-resource.c ++++ b/gom/gom-resource.c +@@ -26,6 +26,7 @@ + #include "gom-repository.h" + #include "gom-resource.h" + #include "gom-resource-priv.h" ++#include "reserved-keywords.h" + + G_DEFINE_ABSTRACT_TYPE(GomResource, gom_resource, G_TYPE_OBJECT) + +@@ -200,6 +201,19 @@ gom_resource_class_set_reference (GomResourceClass *resource_class, + g_strdup(ref_property_name), g_free); + } + ++static gboolean ++is_valid_table_name (const gchar *table) ++{ ++ guint i; ++ ++ for (i = 0; i < G_N_ELEMENTS (reserved_keywords); i++) { ++ if (g_ascii_strcasecmp (reserved_keywords[i], table) == 0) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + void + gom_resource_class_set_table (GomResourceClass *resource_class, + const gchar *table) +@@ -207,6 +221,7 @@ gom_resource_class_set_table (GomResourceClass *resource_class, + g_return_if_fail(GOM_IS_RESOURCE_CLASS(resource_class)); + g_return_if_fail(table != NULL); + g_return_if_fail(strlen(table) <= sizeof(resource_class->table)); ++ g_return_if_fail(is_valid_table_name(table)); + + g_snprintf(resource_class->table, + sizeof(resource_class->table), +-- +2.21.1 (Apple Git-122.3) + diff --git a/0004-tests-And-check-for-assertion-due-to-invalid-table-n.patch b/0004-tests-And-check-for-assertion-due-to-invalid-table-n.patch new file mode 100644 index 0000000..6d9566c --- /dev/null +++ b/0004-tests-And-check-for-assertion-due-to-invalid-table-n.patch @@ -0,0 +1,38 @@ +From 7cb346a0e3f83bffa0bfba5b35ab5e8a27c0a9e2 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Wed, 9 Aug 2017 13:16:01 +0200 +Subject: [PATCH 04/29] tests: And check for assertion due to invalid table + name + +The old test would simply crash when attempting to use a +resource with the invalid table name for the first time. With the +validity checks, we now assert much earlier. Adapt the test to succeed +if the check fails as expected. + +https://bugzilla.gnome.org/show_bug.cgi?id=785983 +--- + tests/test-gom-table-name.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/tests/test-gom-table-name.c b/tests/test-gom-table-name.c +index 7c099d0..d17f661 100644 +--- a/tests/test-gom-table-name.c ++++ b/tests/test-gom-table-name.c +@@ -156,6 +156,14 @@ table_name (void) + char *s1, *s2; + ItemResource *it; + ++ if (!g_test_subprocess ()) { ++ /* Rerun this same test in a subprocess */ ++ g_test_trap_subprocess (NULL, 0, 0); ++ g_test_trap_assert_failed (); ++ g_test_trap_assert_stderr ("*CRITICAL*is_valid_table_name*failed*"); ++ return; ++ } ++ + adapter = gom_adapter_new(); + //ret = gom_adapter_open_sync(adapter, "file:test.db", &error); + ret = gom_adapter_open_sync(adapter, ":memory:", &error); +-- +2.21.1 (Apple Git-122.3) + diff --git a/0005-gom-Store-NULL-GDateTimes-in-the-database-as-NULL.patch b/0005-gom-Store-NULL-GDateTimes-in-the-database-as-NULL.patch new file mode 100644 index 0000000..27ad082 --- /dev/null +++ b/0005-gom-Store-NULL-GDateTimes-in-the-database-as-NULL.patch @@ -0,0 +1,65 @@ +From e80ff4910c8a481fbb0616cd0ef16d6329132da6 Mon Sep 17 00:00:00 2001 +From: Bob Ham +Date: Wed, 17 Jul 2019 14:44:15 +0100 +Subject: [PATCH 12/29] gom: Store NULL GDateTimes in the database as NULL + +Currently Gom will store NULL GDateTimes in the database as a string +representing the epoch, '1970-01-01T00:00:00Z', instead of NULL. This +unneccessarily increases the storage requirements of every NULL +GDateTime column in every row by 20 bytes. This also presents a loss +of information: there's no way to distinguish between the valid input +values of the epoch and NULL. The API user has to account for the way +in which the library is transforming data values. + +To fix this, we store NULL GDateTime values in the database as NULL +instead. +--- + gom/gom-command.c | 6 +++--- + gom/gom-cursor.c | 6 +++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/gom/gom-command.c b/gom/gom-command.c +index a66050c..abad299 100644 +--- a/gom/gom-command.c ++++ b/gom/gom-command.c +@@ -106,13 +106,13 @@ gom_command_bind_param (GomCommand *command, + break; + default: + if (G_VALUE_TYPE(value) == G_TYPE_DATE_TIME) { +- GTimeVal tv = { 0 }; + GDateTime *dt = g_value_get_boxed(value); +- gchar *iso8601; ++ gchar *iso8601 = NULL; + if (dt) { ++ GTimeVal tv = { 0 }; + g_date_time_to_timeval(dt, &tv); ++ iso8601 = g_time_val_to_iso8601(&tv); + } +- iso8601 = g_time_val_to_iso8601(&tv); + sqlite3_bind_text(priv->stmt, param, iso8601, -1, g_free); + break; + } else if (G_VALUE_TYPE(value) == G_TYPE_STRV) { +diff --git a/gom/gom-cursor.c b/gom/gom-cursor.c +index 6d21ae4..6ffdc28 100644 +--- a/gom/gom-cursor.c ++++ b/gom/gom-cursor.c +@@ -86,13 +86,13 @@ gom_cursor_get_column (GomCursor *cursor, + break; + default: + if (G_VALUE_TYPE(value) == G_TYPE_DATE_TIME) { +- GTimeVal tv = { 0 }; +- GDateTime *dt; + const gchar *iso8601 = (gchar *)sqlite3_column_text(priv->stmt, column); ++ GDateTime *dt = NULL; + if (iso8601) { ++ GTimeVal tv = { 0 }; + g_time_val_from_iso8601(iso8601, &tv); ++ dt = g_date_time_new_from_timeval_utc(&tv); + } +- dt = g_date_time_new_from_timeval_utc(&tv); + g_value_take_boxed(value, dt); + break; + } +-- +2.21.1 (Apple Git-122.3) + diff --git a/gom.spec b/gom.spec index bcd5305..1da0baa 100644 --- a/gom.spec +++ b/gom.spec @@ -1,10 +1,17 @@ Name: gom Version: 0.3.3 -Release: 2 +Release: 3 Summary: GObject to SQLite object mapper library License: LGPLv2+ URL: https://wiki.gnome.org/Projects/Gom Source0: https://download.gnome.org/sources/gom/0.3/gom-%{version}.tar.xz + +Patch1: 0001-tests-Add-test-for-invalid-table-names.patch +Patch2: 0002-gom-Add-a-private-header-to-list-reserved-keywords.patch +Patch3: 0003-gom-Verify-whether-a-table-name-is-valid-before-sett.patch +Patch4: 0004-tests-And-check-for-assertion-due-to-invalid-table-n.patch +Patch5: 0005-gom-Store-NULL-GDateTimes-in-the-database-as-NULL.patch + BuildRequires: gobject-introspection-devel gtk-doc meson pkgconfig(gdk-pixbuf-2.0) pkgconfig(gio-2.0) BuildRequires: pkgconfig(gobject-2.0) pkgconfig(sqlite3) pygobject3-devel python3-devel python3-pygments %description @@ -42,6 +49,9 @@ The gom-devel package contains libraries and header files for developing applica %doc %{_datadir}/gtk-doc/ %changelog +* Mon Jul 27 2020 Zhiqiang Liu - 0.3.3-3 +- backport upstream patches. + * Sun Jul 5 2020 Zhiqiang Liu - 0.3.3-2 - remove useless readme files.